gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r20414 - gnunet-fuse


From: gnunet
Subject: [GNUnet-SVN] r20414 - gnunet-fuse
Date: Fri, 9 Mar 2012 15:36:28 +0100

Author: mauricio
Date: 2012-03-09 15:36:28 +0100 (Fri, 09 Mar 2012)
New Revision: 20414

Added:
   gnunet-fuse/directory.c
   gnunet-fuse/dirent.c
   gnunet-fuse/file.c
   gnunet-fuse/getattr.c
   gnunet-fuse/main.c
   gnunet-fuse/mkdir.c
   gnunet-fuse/mknod.c
   gnunet-fuse/open.c
   gnunet-fuse/read.c
   gnunet-fuse/readdir.c
   gnunet-fuse/release.c
   gnunet-fuse/rename.c
   gnunet-fuse/rmdir.c
   gnunet-fuse/special_file.c
   gnunet-fuse/truncate.c
   gnunet-fuse/unlink.c
   gnunet-fuse/utimens.c
   gnunet-fuse/write.c
Removed:
   gnunet-fuse/gnunet-fuse-v8/
Log:
trying to change folder hierarachy


Copied: gnunet-fuse/directory.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/directory.c)
===================================================================
--- gnunet-fuse/directory.c                             (rev 0)
+++ gnunet-fuse/directory.c     2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,429 @@
+/*
+ * directory.c - stuff you want to do with directories
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <GNUnet/gnunet_ecrs_lib.h>
+#include "gnfs.h"
+
+static void dpcb(unsigned long long totalBytes,
+       unsigned long long completedBytes, GNUNET_CronTime eta,
+       unsigned long long lastBlockOffset, const char *lastBlock,
+       unsigned int lastBlockSize, void *cls)
+{
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       memcpy((char *)cls + lastBlockOffset, lastBlock, lastBlockSize);
+}
+
+static int tt(void *cls)
+{
+       (void)cls;
+       if(closing)
+               return GNUNET_OK;
+       if(fuse_interrupted())
+               return GNUNET_SYSERR;
+       return GNUNET_OK;
+}
+
+static int dir_cache_cb(const GNUNET_ECRS_FileInfo *fi, const GNUNET_HashCode 
*key,
+       int isRoot, void *data)
+{
+       struct dirent *de, *deparent = data;
+       gchar *filename, *path, *newpath, type;
+       size_t len, rlen;
+
+       (void)key;
+
+       if(isRoot == GNUNET_YES)
+               return GNUNET_OK;
+
+       /* Figure out the filename and type from metadata */
+       filename = GNUNET_meta_data_get_by_type(fi->meta, EXTRACTOR_FILENAME);
+       if(filename == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | 
GNUNET_GE_WARNING,
+                       "%s: dirent has no filename\n", __FUNCTION__);
+               return GNUNET_OK;
+       }
+       len = strlen(filename);
+       if(GNUNET_meta_data_test_for_directory(fi->meta) == GNUNET_YES)
+       {
+               if(filename[len - 1] == '/' || filename[len - 1] == '\\')
+                       filename[len - 1] = '\0';
+               type = DE_DIR;
+       }
+       else
+               type = DE_FILE;
+
+       /* Create newpath, the path to this entry */
+       path = gn_dirent_path_get(deparent);
+       rlen = strlen(path);
+       newpath = GNUNET_malloc(rlen + len + 1);
+       strcpy(newpath, path);
+       if(path[rlen - 1] != G_DIR_SEPARATOR)
+               strcat(newpath, G_DIR_SEPARATOR_S);
+       GNUNET_free(path);
+       strcat(newpath, filename);
+
+       /* Create a new dirent for this entry only if one doesn't already exist
+        * and the only place that can be is in the cache */
+       de = gn_dirent_get(newpath);
+       if(de == NULL)
+       {
+               de = gn_dirent_new(newpath, fi->uri, fi->meta, type);
+
+               /* Add it to the cache (creates its own ref)*/
+               /* NB: the lock on deparent is enough to guarantee that another
+                * thread hasn't added this dirent to the cache in the time
+                * between the above check and this insert */
+               gn_dirent_cache_insert(de);
+       }
+
+       /* Add it to the directory's list (steals our ref)*/
+       GNUNET_mutex_lock(de->de_path_mutex);
+       GNUNET_GE_ASSERT(ectx,
+               !g_hash_table_lookup(deparent->de_dir_hash, de->de_basename));
+       g_hash_table_replace(deparent->de_dir_hash, de->de_basename, de);
+       GNUNET_mutex_unlock(de->de_path_mutex);
+
+       /* Clean up */
+       GNUNET_free(filename);
+       GNUNET_free(newpath);
+       return GNUNET_OK;
+}
+
+static int directory_cache_locked(struct dirent *de)
+{
+       struct GNUNET_MetaData *md;
+       void *mem;
+       int ret;
+       guint64 len;
+
+       len = GNUNET_ECRS_uri_get_file_size(de->de_fi.uri);
+       mem = GNUNET_malloc(len);
+       ret = GNUNET_ECRS_file_download_partial(ectx, cfg, de->de_fi.uri,
+               "/dev/null", 0, len, anonymity, GNUNET_YES, dpcb, mem, tt,
+               NULL);
+       if(ret != GNUNET_OK)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | 
GNUNET_GE_ERROR,
+                       "%s: failed to download directory\n",
+                       __FUNCTION__);
+               GNUNET_free(mem);
+               return -1;
+       }
+       de->de_dir_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+               (GDestroyNotify)gn_dirent_put);
+       GNUNET_ECRS_directory_list_contents(ectx, mem, len, NULL, &md, 
dir_cache_cb, de);
+       GNUNET_free(mem);
+       GNUNET_meta_data_destroy(md);
+       de->de_cached = 1;
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: cached %d entries\n", __FUNCTION__,
+               g_hash_table_size(de->de_dir_hash));
+       return 0;
+}
+
+struct dir_foreach_data
+{
+       gn_dir_foreach_callback cb;
+       void *data;
+};
+
+static gboolean dir_foreach_callback(gpointer key, gpointer value,
+       gpointer data)
+{
+       struct dirent *de = value;
+       struct dir_foreach_data *d = data;
+
+       (void)key;
+       return d->cb(de, d->data) == -1;
+}
+
+/*
+ * Call cb for each element in a directory
+ */
+int gn_directory_foreach(struct dirent *de, gn_dir_foreach_callback cb,
+       void *data)
+{
+       struct dir_foreach_data d;
+       int ret = 0;
+
+       if(de->de_type != DE_DIR)
+               return -1;
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+               return -1;
+       if(!de->de_cached)
+       {
+               ret = directory_cache_locked(de);
+               if(ret == -1)
+                       goto out;
+       }
+       d.cb = cb;
+       d.data = data;
+       g_hash_table_find(de->de_dir_hash, dir_foreach_callback, &d);
+out:
+       GNUNET_semaphore_up(de->de_sema);
+       return ret;
+}
+
+/*
+ * Finds 'filename' in directory 'de' and returns a reference or NULL
+ */
+struct dirent *gn_directory_find(struct dirent *de, const gchar *filename)
+{
+       struct dirent *ret = NULL;
+
+       if(de->de_type != DE_DIR)
+               return NULL;
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+               return NULL;
+       if(!de->de_cached)
+       {
+               if(directory_cache_locked(de) == -1)
+                       goto out;
+       }
+       ret = g_hash_table_lookup(de->de_dir_hash, filename);
+       if(ret != NULL)
+               gn_dirent_ref(ret);
+out:
+       GNUNET_semaphore_up(de->de_sema);
+       return ret;
+}
+
+int gn_directory_insert(struct dirent *de, struct dirent *dechild)
+{
+       /* Lock our path */
+       if(gn_lock_path(de) == -1)
+               return -1;
+
+       /* Cache ourselfs (because we're going to become dirty) */
+       if(!de->de_cached)
+       {
+               if(directory_cache_locked(de) == -1)
+               {
+                       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | 
GNUNET_GE_DEVELOPER | GNUNET_GE_DEBUG,
+                               "%s: failed to cache parent dir\n",
+                               __FUNCTION__);
+                       gn_unlock_path(de, GN_UNLOCK_CLEAN);
+                       return -1;
+               }
+       }
+
+       /* If we're already in there, bail out */
+       GNUNET_mutex_lock(dechild->de_path_mutex);
+       if(g_hash_table_lookup(de->de_dir_hash, dechild->de_basename))
+       {
+               GNUNET_mutex_unlock(dechild->de_path_mutex);
+               gn_unlock_path(de, GN_UNLOCK_CLEAN);
+               return -1;
+       }
+
+       /* Insert the child in our de_dir_hash */
+       gn_dirent_ref(dechild);
+       g_hash_table_replace(de->de_dir_hash, dechild->de_basename, dechild);
+       GNUNET_mutex_unlock(dechild->de_path_mutex);
+
+       /* Cache the dirent */
+       gn_dirent_cache_insert(dechild);
+
+       /* Mark our path dirty */
+       gn_unlock_path(de, GN_UNLOCK_ALL_DIRTY);
+       return 0;
+}
+
+int gn_directory_remove(struct dirent *de, struct dirent *dechild)
+{
+       /* Lock our path */
+       if(gn_lock_path(de) == -1)
+               return -1;
+
+       /* Cache ourselfs (because we're going to become dirty) */
+       if(!de->de_cached)
+       {
+               if(directory_cache_locked(de) == -1)
+               {
+                       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | 
GNUNET_GE_DEVELOPER | GNUNET_GE_ERROR,
+                               "%s: failed to cache parent dir\n",
+                               __FUNCTION__);
+                       goto out_err;
+               }
+       }
+
+       /* Remove from dir_hash */
+       GNUNET_mutex_lock(dechild->de_path_mutex);
+       if(!g_hash_table_remove(de->de_dir_hash, dechild->de_basename))
+       {
+               GNUNET_mutex_unlock(dechild->de_path_mutex);
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: not found in dir_hash\n",
+                       __FUNCTION__);
+               goto out_err;
+       }
+       GNUNET_mutex_unlock(dechild->de_path_mutex);
+
+       /* Remove from dirent cache */
+       gn_dirent_cache_remove(dechild);
+
+       /* Mark our path dirty */
+       gn_unlock_path(de, GN_UNLOCK_ALL_DIRTY);
+       return 0;
+out_err:
+       gn_unlock_path(de, GN_UNLOCK_CLEAN);
+       return -1;
+}
+
+static void upcb(unsigned long long totalBytes, 
+                unsigned long long completedBytes, GNUNET_CronTime eta,
+       void *closure)
+{
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       (void)closure;
+}
+
+struct dir_upload_data
+{
+       GNUNET_ECRS_FileInfo *fis;
+       int count;
+       int failed;
+};
+
+static gboolean dir_upload_callback(gpointer key, gpointer value, gpointer 
data)
+{
+       struct dirent *de = value;
+       struct dir_upload_data *d = data;
+       int ret = 0;
+
+       (void)key;
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+       {
+               d->failed = 1;
+               return 1;
+       }
+       if(de->de_dirty)
+       {
+               if(de->de_type == DE_FILE)
+               {
+                       if(de->de_fi.uri == NULL)
+                       {
+                               goto out;
+                       }
+               }
+               else
+               {
+                       if(gn_directory_upload_locked(de) == -1)
+                       {
+                               d->failed = 1;
+                               ret = 1;
+                               goto out;
+                       }
+               }
+       }
+       d->fis[d->count].uri = GNUNET_ECRS_uri_duplicate(de->de_fi.uri);
+       d->fis[d->count].meta = GNUNET_meta_data_duplicate(de->de_fi.meta);
+       d->count++;
+out:
+       GNUNET_semaphore_up(de->de_sema);
+       return ret;
+}
+
+/*
+ * Make a directory clean, de_sema must be locked
+ */
+int gn_directory_upload_locked(struct dirent *de)
+{
+       int i, ret, fd;
+       char *buf, filename[] = GN_MKSTEMP_FILE;
+       unsigned long long len;
+       struct GNUNET_ECRS_URI *uri;
+       struct dir_upload_data d;
+
+       /* We may be already clean */
+       if(!de->de_dirty)
+               return 0;
+
+       /* Collect FileInfo from hash table and make a GNUnet directory */
+       d.fis = GNUNET_malloc(g_hash_table_size(de->de_dir_hash) * 
sizeof(*d.fis));
+       d.count = 0;
+       d.failed = 0;
+       g_hash_table_find(de->de_dir_hash, dir_upload_callback, &d);
+       if(d.failed)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: failed\n", __FUNCTION__);
+               return -1;
+       }
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: creating dir of %d elements\n", __FUNCTION__, d.count);
+       ret = GNUNET_ECRS_directory_create(ectx, &buf, &len, d.count, d.fis,
+               de->de_fi.meta);
+       for(i = 0; i < d.count; i++)
+       {
+               GNUNET_ECRS_uri_destroy(d.fis[i].uri);
+               GNUNET_meta_data_destroy(d.fis[i].meta);
+       }
+       GNUNET_free(d.fis);
+       if(ret == GNUNET_SYSERR)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: GNUNET_ECRS_directory_create failed\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       /* Write the GNUnet directory out to a file and upload it */
+       fd = mkstemp(filename);
+       if(fd == -1)
+       {
+               GNUNET_GE_LOG_STRERROR_FILE(ectx, GNUNET_GE_BULK | 
GNUNET_GE_DEVELOPER
+                       | GNUNET_GE_ERROR, "mkstemp", filename);
+               return -1;
+       }
+       write(fd, buf, len);
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: wrote to %lld bytes to '%s'\n", __FUNCTION__, len,
+               filename);
+       ret = GNUNET_ECRS_file_upload(ectx, cfg, filename, GNUNET_NO, 
anonymity, priority,
+               -1, upcb, NULL, tt, NULL, &uri);
+       close(fd);
+       unlink(filename);
+       if(ret == GNUNET_SYSERR)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: GNUNET_ECRS_file_upload failed\n", __FUNCTION__);
+               return -1;
+       }
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: done\n", __FUNCTION__);
+       /* Update the dirent info with our new URI and mark it clean */
+       if(de->de_fi.uri != NULL)
+               GNUNET_ECRS_uri_destroy(de->de_fi.uri);
+       de->de_fi.uri = uri;
+       de->de_dirty = 0;
+       return 0;
+}

Copied: gnunet-fuse/dirent.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/dirent.c)
===================================================================
--- gnunet-fuse/dirent.c                                (rev 0)
+++ gnunet-fuse/dirent.c        2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,385 @@
+/*
+ * dirent.c - stuff for directory entries
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <unistd.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include "gnfs.h"
+
+GHashTable *path_hash;
+struct GNUNET_Semaphore *path_sema;
+
+/*
+ * Reference a dirent, call gn_dirent_put when finished
+ */
+void gn_dirent_ref(struct dirent *de)
+{
+       GNUNET_mutex_lock(de->de_refs_mutex);
+       de->de_refs++;
+       GNUNET_mutex_unlock(de->de_refs_mutex);
+}
+
+/*
+ * Reference a dirent from the cache, call gn_dirent_put when finished with it
+ */
+struct dirent *gn_dirent_get(const gchar *path)
+{
+       struct dirent *de;
+
+       if(GNUNET_semaphore_down(path_sema, GNUNET_YES) == GNUNET_SYSERR)
+               return NULL;
+       de = g_hash_table_lookup(path_hash, path);
+       if(de != NULL)
+               gn_dirent_ref(de);
+       GNUNET_semaphore_up(path_sema);
+       return de;
+}
+
+/*
+ * Release a reference to a dirent
+ */
+void gn_dirent_put(struct dirent *de)
+{
+       GNUNET_mutex_lock(de->de_refs_mutex);
+       de->de_refs--;
+       if(de->de_refs >= 1)
+       {
+               GNUNET_mutex_unlock(de->de_refs_mutex);
+               return;
+       }
+       GNUNET_mutex_unlock(de->de_refs_mutex);
+       GNUNET_mutex_destroy(de->de_path_mutex);
+       GNUNET_free(de->de_path);
+       GNUNET_mutex_destroy(de->de_refs_mutex);
+       GNUNET_semaphore_destroy(de->de_sema);
+       if(de->de_fi.uri != NULL)
+               GNUNET_ECRS_uri_destroy(de->de_fi.uri);
+       if(de->de_fi.meta != NULL)
+               GNUNET_meta_data_destroy(de->de_fi.meta);
+       if(de->de_type == DE_DIR)
+       {
+               if(de->de_cached)
+               {
+                       g_hash_table_destroy(de->de_dir_hash);
+               }
+       }
+       else
+       {
+               if(de->de_cached)
+               {
+                       close(de->de_fd);
+                       unlink(de->de_filename);
+                       GNUNET_free(de->de_filename);
+               }
+       }
+       GNUNET_free(de);
+}
+
+char *gn_dirent_path_get(struct dirent *de)
+{
+       char *ret;
+
+       GNUNET_mutex_lock(de->de_path_mutex);
+       ret = GNUNET_strdup(de->de_path);
+       GNUNET_mutex_unlock(de->de_path_mutex);
+       return ret;
+}
+
+/*
+ * DON'T call this if the dirent is ref'd by a hash
+ */
+void gn_dirent_path_set(struct dirent *de, const char *path)
+{
+       GNUNET_mutex_lock(de->de_path_mutex);
+       GNUNET_free(de->de_path);
+       de->de_path = GNUNET_strdup(path);
+       de->de_basename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1;
+       GNUNET_mutex_unlock(de->de_path_mutex);
+}
+
+void gn_dirent_cache_init(void)
+{
+       path_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+               (GDestroyNotify)gn_dirent_put);
+       path_sema = GNUNET_semaphore_create(1);
+}
+
+/*
+ * Create a new dirent with a reference, path and uri are copied
+ */
+struct dirent *gn_dirent_new(const gchar *path, struct GNUNET_ECRS_URI *uri,
+       struct GNUNET_MetaData *meta, gchar type)
+{
+       struct dirent *de;
+
+       de = GNUNET_malloc(sizeof(*de));
+       de->de_path_mutex = GNUNET_mutex_create(0);
+       de->de_path = GNUNET_strdup(path);
+       de->de_basename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1;
+       de->de_refs_mutex = GNUNET_mutex_create(0);
+       de->de_refs = 1;
+       de->de_type = type;
+       de->de_sema = GNUNET_semaphore_create(1);
+       if(uri != NULL)
+       {
+               de->de_dirty = 0;
+               de->de_cached = 0;
+               de->de_fi.uri = GNUNET_ECRS_uri_duplicate(uri);
+       }
+       else
+       {
+               de->de_dirty = 1;
+               de->de_cached = 1;
+               if(type == DE_FILE)
+               {
+                       char filename[] = GN_MKSTEMP_FILE;
+
+                       de->de_fd = mkstemp(filename);
+                       de->de_filename = GNUNET_strdup(filename);
+               }
+               else
+               {
+                       de->de_dir_hash = g_hash_table_new_full(g_str_hash,
+                               g_str_equal, NULL,
+                               (GDestroyNotify)gn_dirent_put);
+               }
+       }
+       if(meta == NULL)
+               de->de_fi.meta = GNUNET_meta_data_create();
+       else
+               de->de_fi.meta = GNUNET_meta_data_duplicate(meta);
+       return de;
+}
+
+/*
+ * Add a dirent to the cache
+ */
+void gn_dirent_cache_insert(struct dirent *de)
+{
+       /* TODO: Here we need to see if the cache has gotten too big and empty
+        * it.
+        * XXX: But what about diry entries?? */
+       if(GNUNET_semaphore_down(path_sema, GNUNET_YES) == GNUNET_SYSERR)
+               return;
+       GNUNET_mutex_lock(de->de_path_mutex);
+       GNUNET_GE_ASSERT(ectx, !g_hash_table_lookup(path_hash, de->de_path));
+       g_hash_table_replace(path_hash, de->de_path, de);
+       GNUNET_mutex_unlock(de->de_path_mutex);
+       gn_dirent_ref(de);
+       GNUNET_semaphore_up(path_sema);
+}
+
+/*
+ * Remove a dirent from the cache
+ */
+void gn_dirent_cache_remove(struct dirent *de)
+{
+       if(GNUNET_semaphore_down(path_sema, GNUNET_YES) == GNUNET_SYSERR)
+               return;
+       /* This is safe because we still hold a ref */
+       GNUNET_mutex_lock(de->de_path_mutex);
+       g_hash_table_remove(path_hash, de->de_path);
+       GNUNET_mutex_unlock(de->de_path_mutex);
+       GNUNET_semaphore_up(path_sema);
+}
+
+/*
+ * Call 'cb' for each element in 'path', treats the empty string as "/"
+ */
+int gn_path_foreach(const gchar *path, gn_dir_foreach_callback cb, void *data)
+{
+       struct dirent *de, *next_de;
+       size_t len, plen;
+       gchar *ppath, *filename;
+
+       /* Start de off at the root */
+       de = root_de;
+       gn_dirent_ref(de);
+
+       /* Allocate partial path buffer */
+       len = strlen(path);
+       ppath = GNUNET_malloc(len + 1);
+       plen = 0;
+
+       /* Loop through each path element */
+       for( ; ; )
+       {
+               /* Do callback for current element */
+               if(cb(de, data))
+                       break;
+
+               /* Do we have any more work to do? */
+               if(plen >= len || path[plen + 1] == '\0'
+                       || path[plen + 1] == G_DIR_SEPARATOR)
+               {
+                       break;
+               }
+
+               /* Save pointer to ppath end */
+               filename = &ppath[plen + 1];
+
+               /* Cat next path component */
+               ppath[plen] = G_DIR_SEPARATOR;
+               for(plen++; path[plen] != '\0' && path[plen] != G_DIR_SEPARATOR;
+                       plen++)
+               {
+                       ppath[plen] = path[plen];
+               }
+               ppath[plen] = '\0';
+
+               /* Look it up in the cache first */
+               next_de = gn_dirent_get(ppath);
+
+               /* If we found it then continue */
+               if(next_de != NULL)
+               {
+                       gn_dirent_put(de);
+                       de = next_de;
+                       continue;
+               }
+
+               /* We need to find it by listing its parent directory, de */
+               next_de = gn_directory_find(de, filename);
+
+               /* Not found? */
+               if(next_de == NULL)
+               {
+                       gn_dirent_put(de);
+                       de = NULL;
+                       break;
+               }
+
+               /* Continue to the next path element */
+               gn_dirent_put(de);
+               de = next_de;
+       }
+
+       /* Done */
+       GNUNET_free(ppath);
+       if(de == NULL)
+               return -1;
+       gn_dirent_put(de);
+       return 0;
+}
+
+static gboolean dirent_find_callback(struct dirent *de, void *data)
+{
+       struct dirent **d = data;
+
+       if(*d != NULL)
+               gn_dirent_put(*d);
+       *d = de;
+       gn_dirent_ref(*d);
+       return 0;
+}
+
+/*
+ * Retrieve a dirent with a reference given it's (normalized) path.
+ */
+struct dirent *gn_dirent_find(const gchar *path)
+{
+       struct dirent *de = NULL;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: called for '%s'\n", __FUNCTION__, path);
+       if(gn_path_foreach(path, dirent_find_callback, &de) == -1)
+       {
+               if(de != NULL)
+                       gn_dirent_put(de);
+               return NULL;
+       }
+       return de;
+}
+
+static gboolean lock_path_callback(struct dirent *de, void *data)
+{
+       struct dirent **detmp = data;
+
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == -1)
+               return 1;
+       gn_dirent_ref(de);
+       *detmp = de;
+       return 0;
+}
+
+/*
+ * Locks each element in a path.
+ */
+int gn_lock_path(struct dirent *de)
+{
+       struct dirent *detmp = NULL;
+       char *path;
+
+       path = gn_dirent_path_get(de);
+       if(gn_path_foreach(path, lock_path_callback, &detmp) == -1)
+       {
+               GNUNET_free(path);
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: failed!\n", __FUNCTION__);
+               /* Back out all the locks we aquired */
+               if(detmp != NULL)
+                       gn_unlock_path(detmp, GN_UNLOCK_CLEAN);
+               return -1;
+       }
+       GNUNET_free(path);
+       return 0;
+}
+
+struct unlock_path_data
+{
+       int dirty;
+       struct dirent *de;
+};
+
+static gboolean unlock_path_callback(struct dirent *de, void *data)
+{
+       struct unlock_path_data *d = data;
+
+       if(d->dirty == GN_UNLOCK_ALL_DIRTY)
+               de->de_dirty = 1;
+       else if(d->dirty == GN_UNLOCK_ANCESTORS_DIRTY && de != d->de)
+               de->de_dirty = 1;
+       GNUNET_semaphore_up(de->de_sema);
+       gn_dirent_put(de);
+       return 0;
+}
+
+/*
+ * Un-lock each element in a path and set the dirty state
+ */
+int gn_unlock_path(struct dirent *de, int dirty)
+{
+       struct unlock_path_data d;
+       char *path;
+
+       d.dirty = dirty;
+       d.de = de;
+       path = gn_dirent_path_get(de);
+       if(gn_path_foreach(path, unlock_path_callback, &d) == -1)
+       {
+               GNUNET_free(path);
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: failed!\n", __FUNCTION__);
+               return -1;
+       }
+       GNUNET_free(path);
+       return 0;
+}

Copied: gnunet-fuse/file.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/file.c)
===================================================================
--- gnunet-fuse/file.c                          (rev 0)
+++ gnunet-fuse/file.c  2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,126 @@
+/*
+ * file.c - operations on files
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <GNUnet/gnunet_ecrs_lib.h>
+#include "gnfs.h"
+
+static int tt(void *cls)
+{
+       (void)cls;
+       if(closing)
+               return GNUNET_OK;
+       if(fuse_interrupted())
+               return GNUNET_SYSERR;
+       return GNUNET_OK;
+}
+
+static void upcb(unsigned long long totalBytes, 
+                unsigned long long completedBytes, GNUNET_CronTime eta,
+       void *closure)
+{
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       (void)closure;
+}
+
+static void dpcb(unsigned long long totalBytes,
+        unsigned long long completedBytes, GNUNET_CronTime eta,
+        unsigned long long lastBlockOffset, const char *lastBlock,
+        unsigned int lastBlockSize, void *cls)
+{
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       (void)lastBlockOffset;
+       (void)lastBlock;
+       (void)lastBlockSize;
+       (void)cls;
+}
+
+/*
+ * Download a file for writing, de_sema must be held.
+ */
+int gn_file_download_locked(struct dirent *de)
+{
+       char filename[] = GN_MKSTEMP_FILE;
+
+       /* We may already be cached */
+       if(de->de_cached)
+               return 0;
+
+       /* Do the download */
+       de->de_fd = mkstemp(filename);
+       if(de->de_fd == -1)
+       {
+               GNUNET_GE_LOG_STRERROR_FILE(ectx, GNUNET_GE_BULK | 
GNUNET_GE_DEVELOPER
+                       | GNUNET_GE_ERROR, "mkstemp", filename);
+               return -1;
+       }
+       de->de_filename = GNUNET_strdup(filename);
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: downloading '%s'\n", __FUNCTION__, de->de_filename);
+       if(GNUNET_ECRS_file_download(ectx, cfg, de->de_fi.uri, filename, 
anonymity,
+               dpcb, NULL, tt, NULL) == GNUNET_SYSERR)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: download failed\n", __FUNCTION__);
+               close(de->de_fd);
+               unlink(de->de_filename);
+               GNUNET_free(de->de_filename);
+               return -1;
+       }
+
+       /* Mark ourselves cached */
+       de->de_cached = 1;
+       return 0;
+}
+
+int gn_file_upload_locked(struct dirent *de)
+{
+       struct GNUNET_ECRS_URI *uri;
+
+       /* If we're not dirty then we're done */
+       if(!de->de_dirty)
+               return 0;
+
+       if(GNUNET_ECRS_file_upload(ectx, cfg, de->de_filename, GNUNET_NO, 
anonymity, priority,
+               -1, upcb, NULL, tt, NULL, &uri) == GNUNET_SYSERR)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_ERROR,
+                       "%s: upload failed\n", __FUNCTION__);
+               return -1;
+       }
+       if(de->de_fi.uri != NULL)
+               GNUNET_ECRS_uri_destroy(de->de_fi.uri);
+       de->de_fi.uri = uri;
+       de->de_cached = 0;
+       de->de_dirty = 0;
+       close(de->de_fd);
+       unlink(de->de_filename);
+       GNUNET_free(de->de_filename);
+       return 0;
+}

Copied: gnunet-fuse/getattr.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/getattr.c)
===================================================================
--- gnunet-fuse/getattr.c                               (rev 0)
+++ gnunet-fuse/getattr.c       2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,86 @@
+/*
+ * getattr.c - FUSE getattr function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_getattr(const char *path, struct stat *stbuf)
+{
+       struct dirent *de;
+       int ret = 0;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Check to see if this is a special file */
+       if(gn_exists_special_file(path))
+       {
+               memset(stbuf, 0, sizeof(*stbuf));
+               stbuf->st_mode = 0555 | S_IFREG;
+               stbuf->st_nlink = 1;
+               /* sysfs uses 4096 for variable sized files */
+               stbuf->st_size = 4096;
+               return 0;
+       }
+
+       /* Fill in dirent stat info */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | 
GNUNET_GE_DEBUG,
+                       "%s: could not find path '%s'\n", __FUNCTION__, path);
+               return -ENOENT;
+       }
+
+       /* If it's a cached file just call stat */
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+       {
+               gn_dirent_put(de);
+               return -EIO;
+       }
+       if(de->de_cached && de->de_type == DE_FILE)
+       {
+               ret = stat(de->de_filename, stbuf);
+               if(ret == -1)
+               {
+                       ret = -errno;
+                       GNUNET_GE_LOG_STRERROR(ectx, GNUNET_GE_BULK | 
GNUNET_GE_USER | GNUNET_GE_ERROR,
+                               "stat");
+                       goto out;
+               }
+               goto out;
+       }
+
+       memset(stbuf, 0, sizeof(*stbuf));
+       stbuf->st_mode = 0777;
+       stbuf->st_mode |= de->de_type == DE_DIR ? S_IFDIR : S_IFREG;
+       stbuf->st_nlink = 1;
+       if(de->de_fi.uri != NULL)
+               stbuf->st_size = GNUNET_ECRS_uri_get_file_size(de->de_fi.uri);
+       else
+               stbuf->st_size = 0;
+out:
+       GNUNET_semaphore_up(de->de_sema);
+       gn_dirent_put(de);
+       return ret;
+}

Copied: gnunet-fuse/main.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/main.c)
===================================================================
--- gnunet-fuse/main.c                          (rev 0)
+++ gnunet-fuse/main.c  2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,232 @@
+/*
+ * main.c - program start
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+#include <fuse.h>
+#include <GNUnet/gnunet_directories.h>
+#include <GNUnet/gnunet_util.h>
+#include <GNUnet/gnunet_ecrs_lib.h>
+#include "gnfs.h"
+#include "gettext.h"
+
+struct GNUNET_GC_Configuration *cfg;
+struct GNUNET_GE_Context *ectx;
+static char *cfgFilename = GNUNET_DEFAULT_CLIENT_CONFIG_FILE;
+static char *cfgLogfile = "/tmp/gnunet_fuse.log";
+
+/* Flag to indicate that we are shutting down */
+int closing = 0;
+
+/* Level of anonymity for downloading and uploading files */
+unsigned int anonymity = 1;
+
+/* Priority for uploaded files */
+unsigned int priority = 1000;
+
+/* Flag for including .uri files in readdir() */
+int uri_files = 0;
+
+/* argv and argc to pass to fuse, filled in by main and getopt_configure_argv 
*/
+char **fuse_argv;
+int fuse_argc;
+
+/* Root directory entry, currently used by the dirent cache when asked for / */
+int root_fd;
+struct dirent *root_de;
+
+int getopt_configure_argv(GNUNET_CommandLineProcessorContext *ctx, void *scls,
+       const char *cmdLineOption, const char *value)
+{
+       (void)ctx;
+       (void)scls;
+       (void)cmdLineOption;
+
+       fuse_argv[fuse_argc] = (char *)value;
+       fuse_argc++;
+       fuse_argv[fuse_argc] = NULL;
+       return GNUNET_OK;
+}
+
+static struct fuse_operations fops =
+{
+       .getattr = gn_getattr,
+       .mknod = gn_mknod,
+       .mkdir = gn_mkdir,
+       .unlink = gn_unlink,
+       .rmdir = gn_rmdir,
+       .rename = gn_rename,
+       .truncate = gn_truncate,
+       .open = gn_open,
+       .read = gn_read,
+       .write = gn_write,
+       .release = gn_release,
+       .readdir = gn_readdir,
+       .utimens = gn_utimens,
+};
+
+static struct GNUNET_CommandLineOption gn_options[] =
+{
+        GNUNET_COMMAND_LINE_OPTION_HELP("GNUnet filesystem"),
+       GNUNET_COMMAND_LINE_OPTION_CFG_FILE(&cfgFilename), /* -c */
+       GNUNET_COMMAND_LINE_OPTION_LOGGING, /* -L */
+       { 'l', "logfile", "FILE", "set logfile name", 1,
+               &GNUNET_getopt_configure_set_string, &cfgLogfile },
+       { 'a', "anonymity", "LEVEL",
+               "set the desired LEVEL of sender-anonymity", 1,
+               &GNUNET_getopt_configure_set_uint, &anonymity },
+       { 'p', "priority", "LEVEL",
+               "set the desired LEVEL of priority", 1,
+               &GNUNET_getopt_configure_set_uint, &priority },
+       { 'u', "uri-files", NULL, "Make .uri files visible", 0,
+               &GNUNET_getopt_configure_set_one, &uri_files },
+       { 'x', "Xfuse", NULL, "Escape fuse option", 1,
+               &getopt_configure_argv, NULL },
+       GNUNET_COMMAND_LINE_OPTION_END,
+};
+
+int main(int argc, char **argv)
+{
+       int i, ret;
+       struct GNUNET_ECRS_URI *uri;
+       char *buf;
+
+       /* Initialize fuse options */
+       fuse_argc = 1;
+       fuse_argv = GNUNET_malloc(sizeof(char *) * argc);
+       fuse_argv[0] = argv[0];
+       fuse_argv[1] = NULL;
+
+       /* Parse gnunet options */
+       i = GNUNET_init(argc, argv,
+               "gnunet-fuse [OPTIONS] <URI FILE> <MOUNT-POINT>",
+               &cfgFilename, gn_options, &ectx, &cfg);
+       if(i == -1)
+       {
+               ret = -1;
+               goto quit;
+       }
+
+       /* Set up log file */
+       GNUNET_disk_directory_create_for_file(ectx, cfgLogfile);
+       ectx = GNUNET_GE_create_context_logfile(ectx, GNUNET_GE_ALL, 
cfgLogfile, NULL, GNUNET_YES, 0);
+       GNUNET_GE_setDefaultContext(ectx);
+
+       /* There should be exactly two extra arguments */
+       if(i + 2 != argc)
+       {
+               printf("You must specify a URI to mount and mountpoint\n");
+               ret = -1;
+               goto quit;
+       }
+
+       /* Set URI as our root directory entry */
+       gn_dirent_cache_init();
+       if(GNUNET_disk_file_test(ectx, argv[i]) == GNUNET_YES)
+       {
+               unsigned long long len;
+               char *uribuf;
+
+               root_fd = GNUNET_disk_file_open(ectx, argv[i], O_RDWR | O_SYNC);
+               if(root_fd == -1)
+               {
+                       printf("Unable to open URI file: %s\n", argv[i]);
+                       ret = -1;
+                       goto quit;
+               }
+               if(GNUNET_disk_file_size(ectx, argv[i], &len, GNUNET_YES) == 
GNUNET_SYSERR)
+               {
+                       printf("Unable to determine URI file size\n");
+                       ret = -1;
+                       goto out_close_root;
+               }
+               uribuf = GNUNET_malloc(len + 1);
+               read(root_fd, uribuf, len);
+               uribuf[len] = '\0';
+               uri = GNUNET_ECRS_string_to_uri(ectx, uribuf);
+               GNUNET_free(uribuf);
+               if(uri == NULL)
+               {
+                       printf("URI cannot be parsed\n");
+                       ret = -1;
+                       goto out_close_root;
+               }
+               if(!GNUNET_ECRS_uri_test_chk(uri))
+               {
+                       struct GNUNET_ECRS_URI *new_uri;
+
+                       new_uri = GNUNET_ECRS_uri_get_content_uri_from_loc(uri);
+                       if(new_uri == NULL)
+                       {
+                               printf("URI cannot be mounted\n");
+                               ret = -1;
+                               goto out_close_root;
+                       }
+                       GNUNET_ECRS_uri_destroy(uri);
+                       uri = new_uri;
+               }
+               root_de = gn_dirent_new(G_DIR_SEPARATOR_S, uri, NULL, DE_DIR);
+               GNUNET_ECRS_uri_destroy(uri);
+       }
+       else
+       {
+               /* In the case where the file does not exist, let's mount an
+                * empty directory and create the file to store its URI */
+               root_fd = GNUNET_disk_file_open(ectx, argv[i], O_RDWR | O_SYNC
+                       | O_CREAT, 0666);
+               if(root_fd == -1)
+               {
+                       printf("Unable to create URI file: %s\n", argv[i]);
+                       ret = -1;
+                       goto quit;
+               }
+               root_de = gn_dirent_new(G_DIR_SEPARATOR_S, NULL, NULL, DE_DIR);
+       }
+
+       /* Add mount point as the last fuse option */
+       fuse_argv = GNUNET_realloc(fuse_argv, sizeof(char *) * (fuse_argc + 2));
+       fuse_argv[fuse_argc] = argv[i + 1];
+       fuse_argc++;
+       fuse_argv[fuse_argc] = NULL;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_DEBUG, 
"calling fuse_main\n");
+       ret = fuse_main(fuse_argc, fuse_argv, &fops, NULL);
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_DEBUG, 
"fuse_main returned\n");
+
+       /* Save root uri */
+       closing = 1;
+       buf = gn_get_special_file(G_DIR_SEPARATOR_S URI_FILE);
+       if(buf != NULL)
+       {
+               ftruncate(root_fd, 0);
+               lseek(root_fd, SEEK_SET, 0);
+               write(root_fd, buf, strlen(buf));
+               GNUNET_free(buf);
+       }
+out_close_root:
+       GNUNET_disk_file_close(ectx, argv[i], root_fd);
+quit:
+       GNUNET_free(fuse_argv);
+       GNUNET_fini(ectx, cfg);
+       return ret;
+}

Copied: gnunet-fuse/mkdir.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/mkdir.c)
===================================================================
--- gnunet-fuse/mkdir.c                         (rev 0)
+++ gnunet-fuse/mkdir.c 2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,71 @@
+/*
+ * mkdir.c - FUSE mkdir function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_mkdir(const char *path, mode_t mode)
+{
+       struct dirent *de, *newde;
+       struct GNUNET_MetaData *meta;
+       char *parent, *file;
+       int ret;
+
+       (void)mode;
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -EEXIST;
+
+       /* Check for existing file */
+       de = gn_dirent_find(path);
+       if(de != NULL)
+       {
+               gn_dirent_put(de);
+               return -EEXIST;
+       }
+
+       /* Create new directory */
+       parent = gn_dirname(path, &file);
+       de = gn_dirent_find(parent);
+       if(de == NULL)
+       {
+               GNUNET_free(parent);
+               return -ENOENT;
+       }
+       meta = GNUNET_meta_data_create();
+       GNUNET_meta_data_insert(meta, EXTRACTOR_FILENAME, file);
+       GNUNET_meta_data_insert(meta, EXTRACTOR_MIMETYPE, 
GNUNET_DIRECTORY_MIME);
+       newde = gn_dirent_new(path, NULL, meta, DE_DIR);
+       GNUNET_meta_data_destroy(meta);
+       ret = gn_directory_insert(de, newde);
+       gn_dirent_put(de);
+       gn_dirent_put(newde);
+       GNUNET_free(parent);
+       if(ret == -1)
+               return -EIO;
+       return 0;
+}

Copied: gnunet-fuse/mknod.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/mknod.c)
===================================================================
--- gnunet-fuse/mknod.c                         (rev 0)
+++ gnunet-fuse/mknod.c 2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,77 @@
+/*
+ * mknod.c - FUSE mknod function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_mknod(const char *path, mode_t mode, dev_t rdev)
+{
+       struct dirent *de, *newde;
+       struct GNUNET_ECRS_URI *uri;
+       struct GNUNET_MetaData *meta;
+       char *parent, *file;
+       int ret;
+
+       (void)rdev;
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* We only support regular files */
+       if(!S_ISREG(mode))
+               return -ENOTSUP;
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -EEXIST;
+
+       /* Check for existing file */
+       de = gn_dirent_find(path);
+       if(de != NULL)
+       {
+               gn_dirent_put(de);
+               return -EEXIST;
+       }
+
+       /* Create new file */
+       parent = gn_dirname(path, &file);
+       de = gn_dirent_find(parent);
+       if(de == NULL)
+       {
+               GNUNET_free(parent);
+               return -ENOENT;
+       }
+       uri = GNUNET_ECRS_string_to_uri(ectx, GN_EMPTY_FILE_URI);
+       meta = GNUNET_meta_data_create();
+       GNUNET_meta_data_insert(meta, EXTRACTOR_FILENAME, file);
+       GNUNET_free(parent);
+       newde = gn_dirent_new(path, uri, meta, DE_FILE);
+       GNUNET_meta_data_destroy(meta);
+       GNUNET_ECRS_uri_destroy(uri);
+       ret = gn_directory_insert(de, newde);
+       gn_dirent_put(de);
+       gn_dirent_put(newde);
+       if(ret == -1)
+               return -EIO;
+       return 0;
+}

Copied: gnunet-fuse/open.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/open.c)
===================================================================
--- gnunet-fuse/open.c                          (rev 0)
+++ gnunet-fuse/open.c  2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,60 @@
+/*
+ * open.c - FUSE open function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_open(const char *path, struct fuse_file_info *fi)
+{
+       struct dirent *de;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+       
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+       {
+               if(fi->flags & O_WRONLY)
+                       return -EACCES;
+               if((fi->flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+                       return -EEXIST;
+               return 0;
+       }
+
+       /* Check for existing file */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+               return -ENOENT;
+       if(de->de_type != DE_FILE)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: not a file\n", __FUNCTION__);
+               gn_dirent_put(de);
+               return -ENOENT;
+       }
+       gn_dirent_put(de);
+       if((fi->flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               return -EEXIST;
+       return 0;
+}

Copied: gnunet-fuse/read.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/read.c)
===================================================================
--- gnunet-fuse/read.c                          (rev 0)
+++ gnunet-fuse/read.c  2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,168 @@
+/*
+ * read.c - FUSE read function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+struct read_data
+{
+       char *buf;
+       guint size;
+       guint64 offset;
+};
+
+static void dpcb(unsigned long long totalBytes,
+       unsigned long long completedBytes, GNUNET_CronTime eta,
+       unsigned long long lastBlockOffset, const char *lastBlock,
+       unsigned int lastBlockSize, void *cls)
+{
+       struct read_data *d = cls;
+       guint64 block_end = lastBlockOffset + lastBlockSize;
+       guint64 buf_end = d->offset + d->size;
+
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+
+       /* Check if this block is entirely before the buffer */
+       if(block_end < d->offset)
+               return;
+
+       /* Check if this block is entirely after the buffer */
+       if(lastBlockOffset > buf_end)
+               return;
+
+       /* Chop off residue at beginning of block */
+       if(lastBlockOffset < d->offset)
+       {
+               lastBlock += d->offset - lastBlockOffset;
+               lastBlockSize -= d->offset - lastBlockOffset;
+               lastBlockOffset = d->offset;
+       }
+       /* Chop off residue at end of block */
+       if(block_end > buf_end)
+       {
+               lastBlockSize -= block_end - buf_end;
+       }
+       memcpy(d->buf + (lastBlockOffset - d->offset), lastBlock,
+               lastBlockSize);
+}
+
+static int tt(void *cls)
+{
+       (void)cls;
+       return fuse_interrupted() ? GNUNET_SYSERR : GNUNET_OK;
+}
+
+int gn_read(const char *path, char *buf, size_t size, off_t offset,
+       struct fuse_file_info *fi)
+{
+       struct dirent *de;
+       struct read_data d;
+       char *special;
+       int ret;
+       ssize_t slen;
+       guint64 len;
+
+       (void)fi;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: called for '%s' %u bytes %lld offset\n", __FUNCTION__,
+               path, size, offset);
+
+       /* Check for special file */
+       special = gn_get_special_file(path);
+       if(special != NULL)
+       {
+               slen = strlen(special);
+               if(offset >= slen)
+               {
+                       GNUNET_free(special);
+                       return 0;
+               }
+               if( ((ssize_t) (offset + size)) > slen)
+               {
+                       size = slen - offset;
+               }
+               memcpy(buf, special + offset, size);
+               GNUNET_free(special);
+               return size;
+       }
+
+       /* Lookup dirent for path */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: file not found\n", __FUNCTION__);
+               return -ENOENT;
+       }
+       if(de->de_type != DE_FILE)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: not a file\n", __FUNCTION__);
+               size = -ENOENT;
+               goto out;
+       }
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+       {
+               size = -EIO;
+               goto out;
+       }
+       if(de->de_cached)
+       {
+               slen = pread(de->de_fd, buf, size, offset);
+               if(slen == -1)
+                       size = -errno;
+               else
+                       size = slen;
+               goto out_sema_up;
+       }
+       len = GNUNET_ECRS_uri_get_file_size(de->de_fi.uri);
+       if((guint64)offset >= len)
+       {
+               size = 0;
+               goto out_sema_up;
+       }
+       if((guint64)offset + size > len)
+       {
+               size = len - offset;
+       }
+       d.buf = buf;
+       d.size = size;
+       d.offset = offset;
+       ret = GNUNET_ECRS_file_download_partial(ectx, cfg, de->de_fi.uri, 
"/dev/null",
+               offset, size, anonymity, GNUNET_YES, dpcb, &d, tt, NULL);
+       if(ret != GNUNET_OK)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_USER | 
GNUNET_GE_ERROR,
+                       "%s: failed to download file\n", __FUNCTION__);
+               size = -ENODATA;
+       }
+out_sema_up:
+       GNUNET_semaphore_up(de->de_sema);
+out:
+       gn_dirent_put(de);
+       return size;
+}

Copied: gnunet-fuse/readdir.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/readdir.c)
===================================================================
--- gnunet-fuse/readdir.c                               (rev 0)
+++ gnunet-fuse/readdir.c       2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,113 @@
+/*
+ * readdir.c - FUSE readdir function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <fuse.h>
+#include <GNUnet/gnunet_ecrs_lib.h>
+#include "gnfs.h"
+
+struct readdir_callback_data
+{
+       fuse_fill_dir_t filler;
+       void *buf;
+       const char *prefix;
+};
+
+static int readdir_callback(struct dirent *de, void *data)
+{
+       struct readdir_callback_data *d = data;
+
+       (void)de;
+
+       if(d->prefix != NULL)
+       {
+               char *buf = GNUNET_malloc(strlen(d->prefix) + 
strlen(de->de_basename)
+                       + 1);
+
+               sprintf(buf, "%s%s", d->prefix, de->de_basename);
+               d->filler(d->buf, buf, NULL, 0);
+               GNUNET_free(buf);
+       }
+       else
+       {
+               d->filler(d->buf, de->de_basename, NULL, 0);
+       }
+       return GNUNET_OK;
+}
+
+int gn_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+       off_t offset, struct fuse_file_info *fi)
+{
+       struct dirent *de;
+       int ret = 0;
+       struct readdir_callback_data d;
+
+       (void)offset;
+       (void)fi;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "readdir for '%s'\n",
+               path);
+       de = gn_dirent_find(path);
+       if(de == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "readdir: file not found\n");
+               return -ENOENT;
+       }
+       if(de->de_type != DE_DIR)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "readdir: not a directory\n");
+               gn_dirent_put(de);
+               ret = -ENOENT;
+               goto out;
+       }
+       filler(buf, ".", NULL, 0);
+       filler(buf, "..", NULL, 0);
+       if(uri_files)
+       {
+               filler(buf, URI_FILE, NULL, 0);
+               d.filler = filler;
+               d.buf = buf;
+               d.prefix = ".uri.";
+               ret = gn_directory_foreach(de, readdir_callback, &d);
+               if(ret == -1)
+               {
+                       ret = -ENOENT;
+                       goto out;
+               }
+       }
+       d.filler = filler;
+       d.buf = buf;
+       d.prefix = NULL;
+       ret = gn_directory_foreach(de, readdir_callback, &d);
+       if(ret == -1)
+               ret = -ENOENT;
+out:
+       gn_dirent_put(de);
+       return ret;
+}

Copied: gnunet-fuse/release.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/release.c)
===================================================================
--- gnunet-fuse/release.c                               (rev 0)
+++ gnunet-fuse/release.c       2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,63 @@
+/*
+ * release.c - FUSE release function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_release(const char *path, struct fuse_file_info *fi)
+{
+       struct dirent *de;
+       int dirty = GN_UNLOCK_CLEAN;
+
+       (void)fi;
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Don't do anything for special files */
+       if(gn_exists_special_file(path))
+               return 0;
+
+       /* If it doesn't exist we don't care */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+               return 0;
+       if(de->de_type != DE_FILE)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: not a file\n", __FUNCTION__);
+               gn_dirent_put(de);
+               return 0;
+       }
+
+       /* Lock our path */
+       if(gn_lock_path(de) == -1)
+               return 0;
+
+       /* Un-dirty ourselfs */
+       if(gn_file_upload_locked(de) == 0)
+       {
+               /* Now we must mark every containing directory dirty */
+               dirty = GN_UNLOCK_ANCESTORS_DIRTY;
+       }
+
+       gn_unlock_path(de, dirty);
+       gn_dirent_put(de);
+       return 0;
+}

Copied: gnunet-fuse/rename.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/rename.c)
===================================================================
--- gnunet-fuse/rename.c                                (rev 0)
+++ gnunet-fuse/rename.c        2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,135 @@
+/*
+ * rename.c - FUSE rename function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+static gboolean rename_callback(struct dirent *de, void *data)
+{
+       int *empty = data;
+
+       (void)de;
+       *empty = 0;
+       return 1;
+}
+
+int gn_rename(const char *from, const char *to)
+{
+       struct dirent *from_de, *to_de, *from_parent_de, *to_parent_de;
+       char *from_parent, *from_file, *to_parent, *to_file;
+       int ret = 0, empty = 1;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: '%s' to '%s'\n",
+               __FUNCTION__, from, to);
+
+       /* Check for special file */
+       if(gn_exists_special_file(from) || gn_exists_special_file(to))
+               return -EACCES;
+
+       /* Make sure 'from' exists */
+       from_de = gn_dirent_find(from);
+       if(from_de == NULL)
+               return -ENOENT;
+
+       /* We need to check some things before we remove 'from' */
+       to_de = gn_dirent_find(to);
+       if(to_de != NULL)
+       {
+               if(from_de->de_type == DE_FILE && to_de->de_type == DE_DIR)
+               {
+                       ret = -EISDIR;
+                       goto out;
+               }
+               if(from_de->de_type == DE_DIR && to_de->de_type == DE_FILE)
+               {
+                       ret = -ENOTDIR;
+                       goto out;
+               }
+               if(to_de->de_type == DE_DIR)
+               {
+                       gn_directory_foreach(to_de, rename_callback, &empty);
+                       if(!empty)
+                       {
+                               ret = -ENOTEMPTY;
+                               goto out;
+                       }
+               }
+       }
+
+       /* Now we can remove the 'from' */
+       from_parent = gn_dirname(from, &from_file);
+       from_parent_de = gn_dirent_find(from_parent);
+       GNUNET_free(from_parent);
+       if(from_parent_de == NULL)
+       {
+               ret = -ENOENT;
+               goto out;
+       }
+       gn_directory_remove(from_parent_de, from_de);
+       gn_dirent_put(from_parent_de);
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: removed '%s'\n",
+               __FUNCTION__, from);
+
+       /* Modify our path */
+       gn_dirent_path_set(from_de, to);
+
+       /* Replace the 'to' */
+       to_parent = gn_dirname(to, &to_file);
+       to_parent_de = gn_dirent_find(to_parent);
+       GNUNET_free(to_parent);
+       if(to_parent_de == NULL)
+       {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* We should have some kind of directory_remove_insert for atomicity */
+       if(to_de != NULL)
+       {
+               if(gn_directory_remove(to_parent_de, to_de) == -1)
+               {
+                       gn_dirent_put(to_parent_de);
+                       ret = -EIO;
+                       goto out;
+               }
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: removed '%s'\n", __FUNCTION__, to);
+       }
+       if(gn_directory_insert(to_parent_de, from_de) == -1)
+       {
+               gn_dirent_put(to_parent_de);
+               ret = -EIO;
+               goto out;
+       }
+       gn_dirent_put(to_parent_de);
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: inserted '%s'\n", __FUNCTION__, to);
+
+out:
+       if(to_de != NULL)
+               gn_dirent_put(to_de);
+       if(from_de != NULL)
+               gn_dirent_put(from_de);
+       return ret;
+}

Copied: gnunet-fuse/rmdir.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/rmdir.c)
===================================================================
--- gnunet-fuse/rmdir.c                         (rev 0)
+++ gnunet-fuse/rmdir.c 2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,78 @@
+/*
+ * rmdir.c - FUSE rmdir function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+static gboolean rmdir_callback(struct dirent *de, void *data)
+{
+       int *empty = data;
+
+       (void)de;
+       *empty = 0;
+       return 1;
+}
+
+int gn_rmdir(const char *path)
+{
+       struct dirent *de, *dechild;
+       char *parent, *file;
+       int ret, empty = 1;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -ENOTDIR;
+
+       /* Check for existing file */
+       dechild = gn_dirent_find(path);
+       if(dechild == NULL)
+               return -ENOENT;
+
+       /* Can't rmdir a non-empty directory */
+       gn_directory_foreach(dechild, rmdir_callback, &empty);
+       if(!empty)
+       {
+               gn_dirent_put(dechild);
+               return -ENOTEMPTY;
+       }
+
+       /* Remove directory */
+       parent = gn_dirname(path, &file);
+       de = gn_dirent_find(parent);
+       GNUNET_free(parent);
+       if(de == NULL)
+       {
+               gn_dirent_put(dechild);
+               return -ENOENT;
+       }
+       ret = gn_directory_remove(de, dechild);
+       gn_dirent_put(dechild);
+       gn_dirent_put(de);
+       if(ret == -1)
+               return -EIO;
+       return 0;
+}

Copied: gnunet-fuse/special_file.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/special_file.c)
===================================================================
--- gnunet-fuse/special_file.c                          (rev 0)
+++ gnunet-fuse/special_file.c  2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,159 @@
+/*
+ * special_file.c - special file support (like .uri)
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <GNUnet/gnunet_util_string.h>
+#include <GNUnet/gnunet_ecrs_lib.h>
+#include "gnfs.h"
+
+char *gn_dirname(const char *path, char **file)
+{
+       char *parent, *slash;
+
+       parent = GNUNET_strdup(path);
+       slash = strrchr(parent, G_DIR_SEPARATOR);
+       if(slash != NULL)
+       {
+               slash[0] = '\0';
+               slash++;
+       }
+       if(file != NULL)
+               *file = slash;
+       return parent;
+}
+
+/* Checks to see if path is the path to a special file */
+int gn_exists_special_file(const char *path)
+{
+       struct dirent *de;
+       char *file, *parent;
+       int ret = 0;
+
+       parent = gn_dirname(path, &file);
+
+       /* Check for special file name */
+       if(strcmp(file, URI_FILE) == 0)
+       {
+               ret = 1;
+       }
+       else if(strncmp(file, URI_FILE ".", URI_LEN + 1) == 0)
+       {
+               char *actual_file = GNUNET_malloc(strlen(path));
+
+               /* Return URI of the file named after the .uri. */
+               sprintf(actual_file, "%s" G_DIR_SEPARATOR_S "%s", parent,
+                       &file[URI_LEN + 1]);
+               de = gn_dirent_find(actual_file);
+               GNUNET_free(actual_file);
+               if(de == NULL)
+                       goto out;
+               gn_dirent_put(de);
+               ret = 1;
+       }
+out:
+       GNUNET_free(parent);
+       return ret;
+}
+
+/*
+ * Returns a malloc'd string for a special file, and in the case of .uri files
+ * will sync it if it's dirty
+ */
+char *gn_get_special_file(const char *path)
+{
+       struct dirent *de;
+       char *buf = NULL, *file, *parent;
+
+       parent = gn_dirname(path, &file);
+
+       /* Check for special file name */
+       if(strcmp(file, URI_FILE) == 0)
+       {
+               /* Return URI of the 'current' directory */
+               de = gn_dirent_find(parent);
+               if(de == NULL)
+                       goto out;
+               if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == 
GNUNET_SYSERR)
+               {
+                       gn_dirent_put(de);
+                       goto out;
+               }
+               if(de->de_dirty)
+               {
+                       if(gn_directory_upload_locked(de) == -1)
+                       {
+                               GNUNET_semaphore_up(de->de_sema);
+                               gn_dirent_put(de);
+                               goto out;
+                       }
+               }
+               buf = GNUNET_ECRS_uri_to_string(de->de_fi.uri);
+               GNUNET_semaphore_up(de->de_sema);
+               gn_dirent_put(de);
+               buf = GNUNET_realloc(buf, strlen(buf) + 2);
+               strcat(buf, "\n");
+       }
+       else if(strncmp(file, URI_FILE ".", URI_LEN + 1) == 0)
+       {
+               char *actual_file = GNUNET_malloc(strlen(path));
+
+               /* Return URI of the file named after the .uri. */
+               sprintf(actual_file, "%s" G_DIR_SEPARATOR_S "%s", parent,
+                       &file[URI_LEN + 1]);
+               de = gn_dirent_find(actual_file);
+               GNUNET_free(actual_file);
+               if(de == NULL)
+                       goto out;
+               if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == 
GNUNET_SYSERR)
+               {
+                       gn_dirent_put(de);
+                       goto out;
+               }
+               if(de->de_dirty)
+               {
+                       if(de->de_type == DE_DIR)
+                       {
+                               if(gn_directory_upload_locked(de) == -1)
+                               {
+                                       GNUNET_semaphore_up(de->de_sema);
+                                       gn_dirent_put(de);
+                                       goto out;
+                               }
+                       }
+                       else
+                       {
+                               if(de->de_fi.uri == NULL)
+                               {
+                                       GNUNET_semaphore_up(de->de_sema);
+                                       gn_dirent_put(de);
+                                       goto out;
+                               }
+                       }
+               }
+               buf = GNUNET_ECRS_uri_to_string(de->de_fi.uri);
+               GNUNET_semaphore_up(de->de_sema);
+               gn_dirent_put(de);
+               buf = GNUNET_realloc(buf, strlen(buf) + 2);
+               strcat(buf, "\n");
+       }
+out:
+       GNUNET_free(parent);
+       return buf;
+}

Copied: gnunet-fuse/truncate.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/truncate.c)
===================================================================
--- gnunet-fuse/truncate.c                              (rev 0)
+++ gnunet-fuse/truncate.c      2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,90 @@
+/*
+ * truncate.c - FUSE truncate function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_truncate(const char *path, off_t size)
+{
+       struct dirent *de;
+       int ret = 0, dirty = GN_UNLOCK_CLEAN;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: called for '%s' %lld bytes\n", __FUNCTION__, path, size);
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -EACCES;
+
+       /* Lookup dirent for path */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: file not found\n", __FUNCTION__);
+               return -ENOENT;
+       }
+       if(de->de_type != DE_FILE)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: not a file\n", __FUNCTION__);
+               ret = -EISDIR;
+               goto out;
+       }
+
+       /* Lock our path */
+       if(gn_lock_path(de) == -1)
+       {
+               ret = -EIO;
+               goto out;
+       }
+       if(!de->de_cached)
+       {
+               if(gn_file_download_locked(de) == -1)
+               {
+                       ret = -EIO;
+                       goto out_unlock;
+               }
+       }
+
+       /* Perform truncate */
+       ret = ftruncate(de->de_fd, size);
+       if(ret == -1)
+       {
+               ret = -errno;
+               goto out_unlock;
+       }
+
+       /* Mark us dirty */
+       de->de_dirty = 1;
+
+       /* Then un-mark us dirty */
+       if(gn_file_upload_locked(de) == 0)
+       {
+               dirty = GN_UNLOCK_ANCESTORS_DIRTY;
+       }
+out_unlock:
+       gn_unlock_path(de, GN_UNLOCK_ANCESTORS_DIRTY);
+out:
+       gn_dirent_put(de);
+       return ret;
+}

Copied: gnunet-fuse/unlink.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/unlink.c)
===================================================================
--- gnunet-fuse/unlink.c                                (rev 0)
+++ gnunet-fuse/unlink.c        2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,68 @@
+/*
+ * unlink.c - FUSE unlink function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_unlink(const char *path)
+{
+       struct dirent *de, *dechild;
+       char *parent, *file;
+       int ret;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -EPERM;
+
+       /* Check for existing file */
+       dechild = gn_dirent_find(path);
+       if(dechild == NULL)
+               return -ENOENT;
+       
+       /* Can't unlink a directory */
+       if(dechild->de_type != DE_FILE)
+       {
+               gn_dirent_put(dechild);
+               return -EPERM;
+       }
+
+       /* Remove file from parent dir */
+       parent = gn_dirname(path, &file);
+       de = gn_dirent_find(parent);
+       GNUNET_free(parent);
+       if(de == NULL)
+       {
+               gn_dirent_put(dechild);
+               return -ENOENT;
+       }
+       ret = gn_directory_remove(de, dechild);
+       gn_dirent_put(dechild);
+       gn_dirent_put(de);
+       if(ret == -1)
+               return -EIO;
+       return 0;
+}

Copied: gnunet-fuse/utimens.c (from rev 20408, 
gnunet-fuse/gnunet-fuse-v8/utimens.c)
===================================================================
--- gnunet-fuse/utimens.c                               (rev 0)
+++ gnunet-fuse/utimens.c       2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,72 @@
+/*
+ * utimens.c - FUSE utimens function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _GNU_SOURCE
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_utimens(const char *path, const struct timespec ts[2])
+{
+       struct dirent *de;
+       struct timeval tv[2];
+       int ret = 0;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, path);
+
+       /* Check to see if this is a special file */
+       if(gn_exists_special_file(path))
+               return -EACCES;
+
+       /* Get file or dir */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+               return -ENOENT;
+
+       /* If it's a cached file just call utime */
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+       {
+               gn_dirent_put(de);
+               return -EIO;
+       }
+       if(de->de_cached && de->de_type == DE_FILE)
+       {
+               TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
+               TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
+               ret = utimes(path, tv);
+               if(ret == -1)
+               {
+                       ret = -errno;
+                       GNUNET_GE_LOG_STRERROR(ectx, GNUNET_GE_BULK | 
GNUNET_GE_USER | GNUNET_GE_ERROR,
+                               "utimes");
+                       goto out;
+               }
+               goto out;
+       }
+
+       /* For now we do nothing otherwise */
+out:
+       GNUNET_semaphore_up(de->de_sema);
+       gn_dirent_put(de);
+       return ret;
+}

Copied: gnunet-fuse/write.c (from rev 20408, gnunet-fuse/gnunet-fuse-v8/write.c)
===================================================================
--- gnunet-fuse/write.c                         (rev 0)
+++ gnunet-fuse/write.c 2012-03-09 14:36:28 UTC (rev 20414)
@@ -0,0 +1,88 @@
+/*
+ * write.c - FUSE write function
+ *
+ * This file is part of gnunet-fuse.
+ * Copyright (C) 2007 David Barksdale
+ *
+ * gnunet-fuse is free software; you can redistribute it and/or
+ * modify if under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * gnunet-fuse is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+int gn_write(const char *path, const char *buf, size_t size, off_t offset,
+       struct fuse_file_info *fi)
+{
+       struct dirent *de;
+       ssize_t slen;
+
+       (void)fi;
+
+       GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+               "%s: called for '%s' %d bytes\n", __FUNCTION__, path, size);
+
+       /* Check for special file */
+       if(gn_exists_special_file(path))
+               return -EACCES;
+
+       /* Lookup dirent for path */
+       de = gn_dirent_find(path);
+       if(de == NULL)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: file not found\n", __FUNCTION__);
+               return -ENOENT;
+       }
+       if(de->de_type != DE_FILE)
+       {
+               GNUNET_GE_LOG(ectx, GNUNET_GE_BULK | GNUNET_GE_DEVELOPER | 
GNUNET_GE_DEBUG,
+                       "%s: not a file\n", __FUNCTION__);
+               size = -ENOENT;
+               goto out;
+       }
+
+       /* We must be cached */
+       if(GNUNET_semaphore_down(de->de_sema, GNUNET_YES) == GNUNET_SYSERR)
+       {
+               size = -EIO;
+               goto out;
+       }
+       if(!de->de_cached)
+       {
+               if(gn_file_download_locked(de) == -1)
+               {
+                       size = -EIO;
+                       goto out_unlock;
+               }
+       }
+
+       /* Perform write on temp file */
+       slen = pwrite(de->de_fd, buf, size, offset);
+       if(slen == -1)
+               size = -errno;
+       else
+               size = slen;
+
+       /* Mark us dirty */
+       de->de_dirty = 1;
+out_unlock:
+       GNUNET_semaphore_up(de->de_sema);
+out:
+       gn_dirent_put(de);
+       return size;
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]