gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r5302 - gnunet-fuse


From: gnunet
Subject: [GNUnet-SVN] r5302 - gnunet-fuse
Date: Thu, 12 Jul 2007 00:15:51 -0600 (MDT)

Author: amatus
Date: 2007-07-12 00:15:47 -0600 (Thu, 12 Jul 2007)
New Revision: 5302

Added:
   gnunet-fuse/release.c
Modified:
   gnunet-fuse/ChangeLog
   gnunet-fuse/Makefile.am
   gnunet-fuse/configure.ac
   gnunet-fuse/directory.c
   gnunet-fuse/dirent.c
   gnunet-fuse/getattr.c
   gnunet-fuse/gnfs.h
   gnunet-fuse/main.c
   gnunet-fuse/mknod.c
   gnunet-fuse/read.c
   gnunet-fuse/readdir.c
   gnunet-fuse/special_file.c
   gnunet-fuse/write.c
Log:
Added support for creating modifying files

Modified: gnunet-fuse/ChangeLog
===================================================================
--- gnunet-fuse/ChangeLog       2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/ChangeLog       2007-07-12 06:15:47 UTC (rev 5302)
@@ -1,4 +1,6 @@
-2007-06-18 David Barksdale <address@hidden> 0.7.2a
+2007-07-12 David Barksdale <address@hidden> 0.7.2-2
+* Added support for creating and modifying files
+2007-06-18 David Barksdale <address@hidden> 0.7.2-1
 * Modified configure script to better detect compatability with GNUnet
 2007-06-18 David Barksdale <address@hidden> 0.7.2
 * Gratuitous version incrementation

Modified: gnunet-fuse/Makefile.am
===================================================================
--- gnunet-fuse/Makefile.am     2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/Makefile.am     2007-07-12 06:15:47 UTC (rev 5302)
@@ -8,6 +8,7 @@
        open.c \
        read.c \
        readdir.c \
+       release.c \
        special_file.c \
        write.c \
        gnfs.h \

Modified: gnunet-fuse/configure.ac
===================================================================
--- gnunet-fuse/configure.ac    2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/configure.ac    2007-07-12 06:15:47 UTC (rev 5302)
@@ -1,10 +1,11 @@
-AC_INIT(gnunet-fuse, 0.7.2a)
+AC_INIT(gnunet-fuse, 0.7.2)
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(config.h)
 
 AC_PROG_CC
 AM_PROG_CC_C_O
-dnl AC_PROG_LIBTOOL
+AC_C_CHAR_UNSIGNED
+
 export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
 
 PKG_CHECK_MODULES(GLIB, [glib-2.0])
@@ -12,7 +13,7 @@
 
 # test for GNUnet core
 gnunet=0
-AC_MSG_CHECKING(for GNUnet core)
+AC_MSG_CHECKING([for GNUnet core])
 AC_ARG_WITH(gnunet,
    [  --with-gnunet=PFX       Base of GNUnet installation],
    [AC_MSG_RESULT([$with_gnunet])

Modified: gnunet-fuse/directory.c
===================================================================
--- gnunet-fuse/directory.c     2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/directory.c     2007-07-12 06:15:47 UTC (rev 5302)
@@ -40,24 +40,19 @@
 static int tt(void *cls)
 {
        (void)cls;
-       return fuse_interrupted() ? SYSERR : OK;
+       if(closing)
+               return OK;
+       if(fuse_interrupted())
+               return SYSERR;
+       return OK;
 }
 
-struct dir_for_each_data
-{
-       gn_dir_for_each_callback cb;
-       void *data;
-       struct dirent *de;
-};
-
-static int dir_for_each_cb(const ECRS_FileInfo *fi, const HashCode512 *key,
+static int dir_cache_cb(const ECRS_FileInfo *fi, const HashCode512 *key,
        int isRoot, void *data)
 {
-       struct dir_for_each_data *d = data;
-       struct dirent *de;
+       struct dirent *de, *deparent = data;
        gchar *filename, *newpath, type;
        size_t len, rlen;
-       int ret;
 
        (void)key;
 
@@ -83,133 +78,311 @@
                type = DE_FILE;
 
        /* Create newpath, the path to this entry */
-       rlen = strlen(d->de->de_path);
+       rlen = strlen(deparent->de_path);
        newpath = MALLOC(rlen + len + 1);
-       strcpy(newpath, d->de->de_path);
-       if(d->de->de_path[rlen - 1] != G_DIR_SEPARATOR)
+       strcpy(newpath, deparent->de_path);
+       if(deparent->de_path[rlen - 1] != G_DIR_SEPARATOR)
                strcat(newpath, G_DIR_SEPARATOR_S);
        strcat(newpath, filename);
 
-       /* Create a new dirent for this entry */
-       de = gn_dirent_new(newpath, fi->uri, fi->meta, type);
+       /* 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 */
-       gn_dirent_cache(de);
+               /* 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(de);
+       }
 
-       /* Call the callback function */
-       ret = d->cb(de, filename, d->data);
+       /* Add it to the directory's list (steals our ref)*/
+       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);
 
        /* Clean up */
-       gn_dirent_put(de);
        FREE(filename);
        FREE(newpath);
-       return ret;
+       return OK;
 }
 
-static gboolean hash_foreach_cb(gpointer key, gpointer value, gpointer data)
+static int directory_cache_locked(struct dirent *de)
 {
-       struct dir_for_each_data *d = data;
-       struct dirent *de = value;
-       char *filename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1;
+       struct ECRS_MetaData *md;
+       void *mem;
        int ret;
+       guint64 len;
 
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, de->de_path);
+       len = ECRS_fileSize(de->de_fi.uri);
+       mem = MALLOC(len);
+       ret = ECRS_downloadPartialFile(ectx, cfg, de->de_fi.uri,
+               "/dev/null", anonymity, 0, len, YES, dpcb, mem, tt,
+               NULL);
+       if(ret != OK)
+       {
+               GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR,
+                       "%s: failed to download directory\n",
+                       __FUNCTION__);
+               FREE(mem);
+               return -1;
+       }
+       de->de_dir_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+               (GDestroyNotify)gn_dirent_put);
+       ECRS_listDirectory(ectx, mem, len, &md, dir_cache_cb, de);
+       FREE(mem);
+       ECRS_freeMetaData(md);
+       de->de_cached = 1;
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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;
-
-       gn_dirent_ref(de);
-       ret = d->cb(de, filename, d->data);
-       gn_dirent_put(de);
-       return ret == SYSERR;
+       return d->cb(de, d->data) == -1;
 }
 
-int gn_directory_for_each(struct dirent *de, gn_dir_for_each_callback cb,
+/*
+ * Call cb for each element in a directory
+ */
+int gn_directory_foreach(struct dirent *de, gn_dir_foreach_callback cb,
        void *data)
 {
-       struct ECRS_MetaData *md;
-       struct dir_for_each_data d;
-       void *mem;
-       int ret;
-       guint64 len;
+       struct dir_foreach_data d;
+       int ret = 0;
 
        if(de->de_type != DE_DIR)
                return -1;
-       d.cb = cb;
-       d.data = data;
-       d.de = de;
-       if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
                return -1;
-       if(de->de_dirty)
+       if(!de->de_cached)
        {
-               g_hash_table_find(de->de_dir, hash_foreach_cb, &d);
-               SEMAPHORE_UP(de->de_file_sema);
-               return 0;
+               ret = directory_cache_locked(de);
+               if(ret == -1)
+                       goto out;
        }
-       len = ECRS_fileSize(de->de_fi.uri);
-       mem = MALLOC(len);
-       ret = ECRS_downloadPartialFile(ectx, cfg, de->de_fi.uri, "/dev/null",
-               anonymity, 0, len, YES, dpcb, mem, tt, NULL);
-       SEMAPHORE_UP(de->de_file_sema);
-       if(ret != OK)
+       d.cb = cb;
+       d.data = data;
+       g_hash_table_find(de->de_dir_hash, dir_foreach_callback, &d);
+out:
+       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(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
+               return NULL;
+       if(!de->de_cached)
        {
-               GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR,
-                       "%s: failed to download directory\n", __FUNCTION__);
-               ret = -1;
-               goto out;
+               if(directory_cache_locked(de) == -1)
+                       goto out;
        }
-       ECRS_listDirectory(ectx, mem, len, &md, dir_for_each_cb, &d);
-       ECRS_freeMetaData(md);
-       ret = 0;
+       ret = g_hash_table_lookup(de->de_dir_hash, filename);
+       if(ret != NULL)
+               gn_dirent_ref(ret);
 out:
-       FREE(mem);
+       SEMAPHORE_UP(de->de_sema);
        return ret;
 }
 
-static int directory_insert_callback(struct dirent *de, const gchar *filename,
-       void *data)
+int gn_directory_insert(struct dirent *de, struct dirent *dechild)
 {
-       struct dir_for_each_data *d = data;
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n",
+               __FUNCTION__, dechild->de_path);
 
-       (void)filename;
-       gn_dirent_ref(de);
-       g_hash_table_replace(d->de->de_dir, de->de_path, de);
-       return OK;
+       /* 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)
+               {
+                       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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 */
+       if(g_hash_table_lookup(de->de_dir_hash, dechild->de_basename))
+       {
+               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);
+
+       /* Cache the dirent */
+       gn_dirent_cache(dechild);
+
+       /* Mark our path dirty */
+       gn_unlock_path(de, GN_UNLOCK_ALL_DIRTY);
+       return 0;
 }
 
-int gn_directory_insert(struct dirent *de_dir, struct dirent *de_new)
+static void upcb(guint64 totalBytes, guint64 completedBytes, cron_t eta,
+       void *closure)
 {
-       struct dir_for_each_data d;
-       void *mem;
-       guint64 len;
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       (void)closure;
+}
+
+struct dir_upload_data
+{
+       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;
-       struct ECRS_MetaData *md;
 
-       if(SEMAPHORE_DOWN(de_dir->de_file_sema, YES) == SYSERR)
-               return -1;
-       if(!de_dir->de_dirty)
+       (void)key;
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
        {
-               de_dir->de_dirty = 1;
-               de_dir->de_dir = g_hash_table_new_full(g_str_hash, g_str_equal,
-                       NULL, (GDestroyNotify)gn_dirent_put);
-               d.cb = directory_insert_callback;
-               d.de = de_dir;
-               len = ECRS_fileSize(de_dir->de_fi.uri);
-               mem = MALLOC(len);
-               ret = ECRS_downloadPartialFile(ectx, cfg, de_dir->de_fi.uri,
-                       "/dev/null", anonymity, 0, len, YES, dpcb, mem, tt,
-                       NULL);
-               if(ret != OK)
+               d->failed = 1;
+               return 1;
+       }
+       if(de->de_dirty)
+       {
+               if(de->de_type == DE_FILE)
                {
-                       GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR,
-                               "%s: failed to download directory\n",
-                               __FUNCTION__);
-                       ret = -1;
-                       goto out;
+                       if(de->de_fi.uri == NULL)
+                       {
+                               goto out;
+                       }
                }
-               ECRS_listDirectory(ectx, mem, len, &md, dir_for_each_cb, &d);
-               ECRS_freeMetaData(md);
+               else
+               {
+                       if(gn_directory_upload_locked(de) == -1)
+                       {
+                               d->failed = 1;
+                               ret = 1;
+                               goto out;
+                       }
+               }
        }
-       gn_dirent_ref(de_new);
-       g_hash_table_replace(de_dir->de_dir, de_new->de_path, de_new);
+       d->fis[d->count].uri = ECRS_dupUri(de->de_fi.uri);
+       d->fis[d->count].meta = ECRS_dupMetaData(de->de_fi.meta);
+       d->count++;
 out:
-       SEMAPHORE_UP(de_dir->de_file_sema);
+       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;
+       guint64 len;
+       struct ECRS_URI *uri;
+       struct dir_upload_data d;
+
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: called for '%s'\n", __FUNCTION__, de->de_path);
+
+       /* We may be already clean */
+       if(!de->de_dirty)
+               return 0;
+
+       /* Collect FileInfo from hash table and make a GNUnet directory */
+       d.fis = 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)
+       {
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
+                       "%s: failed\n", __FUNCTION__);
+               return -1;
+       }
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: creating dir of %d elements\n", __FUNCTION__, d.count);
+       ret = ECRS_createDirectory(ectx, &buf, &len, d.count, d.fis,
+               de->de_fi.meta);
+       for(i = 0; i < d.count; i++)
+       {
+               ECRS_freeUri(d.fis[i].uri);
+               ECRS_freeMetaData(d.fis[i].meta);
+       }
+       FREE(d.fis);
+       if(ret == SYSERR)
+       {
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
+                       "%s: ECRS_createDirectory failed\n",
+                       __FUNCTION__);
+               return -1;
+       }
+
+       /* Write the GNUnet directory out to a file and upload it */
+       fd = mkstemp(filename);
+       if(fd == -1)
+       {
+               GE_LOG_STRERROR_FILE(ectx, GE_BULK | GE_DEVELOPER
+                       | GE_ERROR, "mkstemp", filename);
+               return -1;
+       }
+       write(fd, buf, len);
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: wrote to %lld bytes to '%s'\n", __FUNCTION__, len,
+               filename);
+       ret = ECRS_uploadFile(ectx, cfg, filename, NO, anonymity, priority,
+               -1, upcb, NULL, tt, NULL, &uri);
+       close(fd);
+       unlink(filename);
+       if(ret == SYSERR)
+       {
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
+                       "%s: ECRS_uploadFile failed\n", __FUNCTION__);
+               return -1;
+       }
+
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: done\n", __FUNCTION__);
+       /* Update the dirent info with our new URI and mark it clean */
+       if(de->de_fi.uri != NULL)
+               ECRS_freeUri(de->de_fi.uri);
+       de->de_fi.uri = uri;
+       de->de_dirty = 0;
+       return 0;
+}

Modified: gnunet-fuse/dirent.c
===================================================================
--- gnunet-fuse/dirent.c        2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/dirent.c        2007-07-12 06:15:47 UTC (rev 5302)
@@ -32,9 +32,9 @@
  */
 void gn_dirent_ref(struct dirent *de)
 {
-       MUTEX_LOCK(de->de_mutex);
+       MUTEX_LOCK(de->de_refs_mutex);
        de->de_refs++;
-       MUTEX_UNLOCK(de->de_mutex);
+       MUTEX_UNLOCK(de->de_refs_mutex);
 }
 
 /*
@@ -58,35 +58,38 @@
  */
 void gn_dirent_put(struct dirent *de)
 {
-       MUTEX_LOCK(de->de_mutex);
+       MUTEX_LOCK(de->de_refs_mutex);
        de->de_refs--;
-       if(de->de_refs < 1)
+       if(de->de_refs >= 1)
        {
-               MUTEX_UNLOCK(de->de_mutex);
-               MUTEX_DESTROY(de->de_mutex);
-               FREE(de->de_path);
-               SEMAPHORE_DESTROY(de->de_file_sema);
-               if(de->de_fi.uri != NULL)
-                       ECRS_freeUri(de->de_fi.uri);
-               if(de->de_fi.meta != NULL)
-                       ECRS_freeMetaData(de->de_fi.meta);
-               if(de->de_dirty)
+               MUTEX_UNLOCK(de->de_refs_mutex);
+               return;
+       }
+       MUTEX_UNLOCK(de->de_refs_mutex);
+       MUTEX_DESTROY(de->de_refs_mutex);
+       FREE(de->de_path);
+       SEMAPHORE_DESTROY(de->de_sema);
+       if(de->de_fi.uri != NULL)
+               ECRS_freeUri(de->de_fi.uri);
+       if(de->de_fi.meta != NULL)
+               ECRS_freeMetaData(de->de_fi.meta);
+       if(de->de_type == DE_DIR)
+       {
+               if(de->de_cached)
                {
-                       if(de->de_type == DE_FILE)
-                       {
-                               close(de->de_fd);
-                               unlink(de->de_filename);
-                               FREE(de->de_filename);
-                       }
-                       else
-                       {
-                               g_hash_table_destroy(de->de_dir);
-                       }
+                       g_hash_table_destroy(de->de_dir_hash);
                }
-               FREE(de);
-               return;
        }
-       MUTEX_UNLOCK(de->de_mutex);
+       else
+       {
+               if(de->de_cached)
+               {
+                       close(de->de_fd);
+                       unlink(de->de_filename);
+                       FREE(de->de_filename);
+               }
+       }
+       FREE(de);
 }
 
 void gn_dirent_cache_init(void)
@@ -106,18 +109,21 @@
 
        de = MALLOC(sizeof(*de));
        de->de_path = STRDUP(path);
-       de->de_mutex = MUTEX_CREATE(0);
+       de->de_basename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1;
+       de->de_refs_mutex = MUTEX_CREATE(0);
        de->de_refs = 1;
        de->de_type = type;
-       de->de_file_sema = SEMAPHORE_CREATE(1);
+       de->de_sema = SEMAPHORE_CREATE(1);
        if(uri != NULL)
        {
-               de->de_fi.uri = ECRS_dupUri(uri);
                de->de_dirty = 0;
+               de->de_cached = 0;
+               de->de_fi.uri = ECRS_dupUri(uri);
        }
        else
        {
                de->de_dirty = 1;
+               de->de_cached = 1;
                if(type == DE_FILE)
                {
                        char filename[] = GN_MKSTEMP_FILE;
@@ -127,12 +133,14 @@
                }
                else
                {
-                       de->de_dir = g_hash_table_new_full(g_str_hash,
-                               g_str_equal, NULL,
+                       g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                (GDestroyNotify)gn_dirent_put);
                }
        }
-       de->de_fi.meta = ECRS_dupMetaData(meta);
+       if(meta == NULL)
+               de->de_fi.meta = ECRS_createMetaData();
+       else
+               de->de_fi.meta = ECRS_dupMetaData(meta);
        return de;
 }
 
@@ -141,77 +149,62 @@
  */
 void gn_dirent_cache(struct dirent *de)
 {
-       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
-               "%s: path '%s'\n", __FUNCTION__, de->de_path);
        /* TODO: Here we need to see if the cache has gotten too big and empty
-        * it */
-       gn_dirent_ref(de);
+        * it.
+        * XXX: But what about diry entries?? */
        if(SEMAPHORE_DOWN(path_sema, YES) == SYSERR)
                return;
+       GE_ASSERT(ectx, !g_hash_table_lookup(path_hash, de->de_path));
        g_hash_table_replace(path_hash, de->de_path, de);
+       gn_dirent_ref(de);
        SEMAPHORE_UP(path_sema);
 }
 
-struct dirent_find_data
-{
-       const gchar *name;
-       struct dirent **de;
-       gboolean found;
-};
-
-static gboolean dirent_find(struct dirent *de, const gchar *filename,
-       void *data)
-{
-       struct dirent_find_data *dfd = data;
-
-       if(dfd->found == 1 || strcmp(filename, dfd->name) != 0)
-               return OK;
-
-       dfd->found = 1;
-       gn_dirent_ref(de);
-       *dfd->de = de;
-       return SYSERR; /* It would be nice if this actually worked */
-}
-
 /*
- * Retrieve a dirent with a reference given it's (normalized) path.
+ * Call 'cb' for each element in 'path', treats the empty string as "/"
  */
-struct dirent *gn_dirent_find(const gchar *path)
+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;
-       struct dirent_find_data dfd;
+       gchar *ppath, *filename;
 
        /* Start de off at the root */
        de = root_de;
        gn_dirent_ref(de);
 
-       /* Root shortcut */
-       if(strcmp(path, G_DIR_SEPARATOR_S) == 0)
-               return de;
-
-       /* Allocate partial path buffer and start it at the root */
+       /* Allocate partial path buffer */
        len = strlen(path);
        ppath = MALLOC(len + 1);
        plen = 0;
 
-       /* Save pointer to next de for the callback function */
-       dfd.de = &next_de;
-
-       /* While we haven't reached the end of path, we have work to do */
-       while(plen < len)
+       /* 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 */
-               dfd.name = &ppath[plen + 1];
+               filename = &ppath[plen + 1];
 
                /* Cat next path component */
-               ppath[plen++] = G_DIR_SEPARATOR;
-               for(;path[plen] != '\0' && path[plen] != G_DIR_SEPARATOR;plen++)
+               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 */
+               /* Look it up in the cache first */
                next_de = gn_dirent_get(ppath);
 
                /* If we found it then continue */
@@ -226,154 +219,125 @@
                }
 
                /* We need to find it by listing its parent directory, de */
-               if(de->de_type != DE_DIR)
-               {
-                       gn_dirent_put(de);
-                       de = NULL;
-                       break;
-               }
-               dfd.found = 0;
-               gn_directory_for_each(de, dirent_find, &dfd);
+               next_de = gn_directory_find(de, filename);
 
-               /* Not found? Then why did they ask us? */
-               if(!dfd.found)
+               /* Not found? */
+               if(next_de == NULL)
                {
-                       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
-                               "%s: not found!\n", __FUNCTION__);
                        gn_dirent_put(de);
                        de = NULL;
                        break;
                }
-
-               /* Continue to the next path element */
                GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
                        "%s: found in directory '%s'\n", __FUNCTION__,
                        next_de->de_path);
+
+               /* Continue to the next path element */
                gn_dirent_put(de);
                de = next_de;
        }
 
        /* Done */
        FREE(ppath);
-
-       return de;
+       if(de == NULL)
+               return -1;
+       gn_dirent_put(de);
+       return 0;
 }
 
-struct upload_data
+static gboolean dirent_find_callback(struct dirent *de, void *data)
 {
-       int count;
-       ECRS_FileInfo *fis;
-};
+       struct dirent **d = data;
 
-static void upload_foreach(gpointer key, gpointer value, gpointer 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 = value;
-       struct upload_data *d = data;
+       struct dirent *de = NULL;
 
-       (void)key;
-
-       if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
-               return;
-       if(de->de_dirty)
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: called for '%s'\n", __FUNCTION__, path);
+       if(gn_path_foreach(path, dirent_find_callback, &de) == -1)
        {
-               if(de->de_type == DE_FILE)
-               {
-                       if(de->de_fi.uri == NULL)
-                               goto out;
-               }
-               else
-               {
-                       gn_dirent_upload_locked(de);
-               }
+               if(de != NULL)
+                       gn_dirent_put(de);
+               return NULL;
        }
-       d->fis[d->count].uri = ECRS_dupUri(de->de_fi.uri);
-       d->fis[d->count].meta = ECRS_dupMetaData(de->de_fi.meta);
-       d->count++;
-out:
-       SEMAPHORE_UP(de->de_file_sema);
+       return de;
 }
 
-static void upcb(guint64 totalBytes, guint64 completedBytes, cron_t eta,
-       void *closure)
+static gboolean lock_path_callback(struct dirent *de, void *data)
 {
-       (void)totalBytes;
-       (void)completedBytes;
-       (void)eta;
-       (void)closure;
-}
+       struct dirent **detmp = data;
 
-static int tt(void *closure)
-{
-       (void)closure;
-
-       return fuse_interrupted() ? SYSERR : OK;
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == -1)
+               return 1;
+       gn_dirent_ref(de);
+       *detmp = de;
+       return 0;
 }
 
 /*
- * Make a dirty dirent clean - it should be a good tradeoff to only upload
- * changes to directories here and upload changes to files on release
+ * Locks each element in a path.
  */
-int gn_dirent_upload_locked(struct dirent *de)
+int gn_lock_path(struct dirent *de)
 {
-       int i, ret, fd;
-       struct upload_data d;
-       char *buf, filename[] = GN_MKSTEMP_FILE;
-       guint64 len;
-       struct ECRS_URI *uri;
+       struct dirent *detmp = NULL;
 
-       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
-               "%s: called for '%s'\n", __FUNCTION__, de->de_path);
-
-       /* We may be already clean */
-       if(!de->de_dirty)
-               return 0;
-       
-       /* Collect FileInfo from hash table and make a GNUnet directory*/
-       d.count = 0;
-       d.fis = MALLOC(g_hash_table_size(de->de_dir) * sizeof(*d.fis));
-       g_hash_table_foreach(de->de_dir, upload_foreach, &d);
-       ret = ECRS_createDirectory(ectx, &buf, &len, d.count, d.fis,
-               de->de_fi.meta);
-       for(i = 0; i < d.count; i++)
+       if(gn_path_foreach(de->de_path, lock_path_callback, &detmp) == -1)
        {
-               ECRS_freeUri(d.fis[i].uri);
-               ECRS_freeMetaData(d.fis[i].meta);
-       }
-       if(ret == SYSERR)
-       {
                GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
-                       "%s: ECRS_createDirectory failed\n",
-                       __FUNCTION__);
+                       "%s: failed!\n", __FUNCTION__);
+               /* Back out all the locks we aquired */
+               if(detmp != NULL)
+                       gn_unlock_path(detmp, GN_UNLOCK_CLEAN);
                return -1;
        }
-       FREE(d.fis);
+       return 0;
+}
 
-       /* Write the GNUnet directory out to a file and upload it */
-       fd = mkstemp(filename);
-       if(fd == -1)
+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;
+       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;
+
+       d.dirty = dirty;
+       d.de = de;
+       if(gn_path_foreach(de->de_path, unlock_path_callback, &d) == -1)
        {
-               GE_LOG_STRERROR_FILE(ectx, GE_BULK | GE_DEVELOPER
-                       | GE_ERROR, "mkstemp", filename);
-               return -1;
-       }
-       write(fd, buf, len);
-       ret = ECRS_uploadFile(ectx, cfg, filename, NO, anonymity, priority,
-               -1, upcb, NULL, tt, NULL, &uri);
-       close(fd);
-       unlink(filename);
-       if(ret == SYSERR)
-       {
                GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
-                       "%s: ECRS_uploadFile failed\n", __FUNCTION__);
+                       "%s: failed!\n", __FUNCTION__);
                return -1;
        }
-
-       /* Update the dirent info with our new URI and mark it clean */
-       if(de->de_fi.uri != NULL)
-               ECRS_freeUri(de->de_fi.uri);
-       de->de_fi.uri = uri;
-       g_hash_table_destroy(de->de_dir);
-       de->de_dirty = 0;
        return 0;
 }
 
@@ -391,15 +355,23 @@
        (void)cls;
 }
 
+static int tt(void *closure)
+{
+       (void)closure;
+       return fuse_interrupted() ? SYSERR : OK;
+}
+
 /*
- * Download a file for writing, de_file_sema must be held.
+ * Download a file for writing, de_sema must be held.
  */
 int gn_dirent_download_locked(struct dirent *de)
 {
        char filename[] = GN_MKSTEMP_FILE;
 
-       /* We may already be dirty */
-       if(!de->de_dirty)
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: called for '%s'\n",
+               __FUNCTION__, de->de_path);
+       /* We may already be cached */
+       if(de->de_cached)
                return 0;
 
        /* Do the download */
@@ -412,16 +384,20 @@
        }
        de->de_filename = STRDUP(filename);
 
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: downloading '%s'\n", __FUNCTION__, de->de_filename);
        if(ECRS_downloadFile(ectx, cfg, de->de_fi.uri, filename, anonymity,
                dpcb, NULL, tt, NULL) == SYSERR)
        {
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
+                       "%s: download failed\n", __FUNCTION__);
                close(de->de_fd);
+               unlink(de->de_filename);
                FREE(de->de_filename);
                return -1;
        }
 
-       /* Mark ourselves dirty, we don't have to mark our parent directory
-        * dirty until we sync this file back into GNUnet, see above. */
-       de->de_dirty = 1;
+       /* Mark ourselves cached */
+       de->de_cached = 1;
        return 0;
 }

Modified: gnunet-fuse/getattr.c
===================================================================
--- gnunet-fuse/getattr.c       2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/getattr.c       2007-07-12 06:15:47 UTC (rev 5302)
@@ -38,7 +38,8 @@
                memset(stbuf, 0, sizeof(*stbuf));
                stbuf->st_mode = 0555 | S_IFREG;
                stbuf->st_nlink = 1;
-               stbuf->st_size = 0;
+               /* sysfs uses 4096 for variable sized files */
+               stbuf->st_size = 4096;
                return 0;
        }
 
@@ -55,9 +56,9 @@
        stbuf->st_mode = 0777;
        stbuf->st_mode |= de->de_type == DE_DIR ? S_IFDIR : S_IFREG;
        stbuf->st_nlink = 1;
-       if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
                return -EIO;
-       if(de->de_dirty)
+       if(de->de_cached)
        {
                if(de->de_type == DE_FILE && disk_file_size(ectx,
                        de->de_filename, &size, NO) == SYSERR)
@@ -65,7 +66,7 @@
                        GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR,
                                "%s: disk_file_size failed for '%s'\n",
                                __FUNCTION__, de->de_filename);
-                       SEMAPHORE_UP(de->de_file_sema);
+                       SEMAPHORE_UP(de->de_sema);
                        gn_dirent_put(de);
                        return -EIO;
                }
@@ -74,7 +75,7 @@
        {
                size = ECRS_fileSize(de->de_fi.uri);
        }
-       SEMAPHORE_UP(de->de_file_sema);
+       SEMAPHORE_UP(de->de_sema);
        gn_dirent_put(de);
        stbuf->st_size = size;
        return 0;

Modified: gnunet-fuse/gnfs.h
===================================================================
--- gnunet-fuse/gnfs.h  2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/gnfs.h  2007-07-12 06:15:47 UTC (rev 5302)
@@ -35,26 +35,33 @@
 #define URI_FILE       ".uri"
 #define URI_LEN                4
 #define GN_MKSTEMP_FILE        "/tmp/gnfs.XXXXXX"
+#define GN_EMPTY_FILE_URI "gnunet://ecrs/chk/00000000000000000000000000000000" 
\
+       "00000000000000000000000000000000000000000000000000000000000000000000" \
+       "000.0000000000000000000000000000000000000000000000000000000000000000" \
+       "000000000000000000000000000000000000000.0"
 
 struct dirent
 {
        gchar *de_path;
-       struct MUTEX *de_mutex;
+       gchar *de_basename;
+       struct MUTEX *de_refs_mutex;
        gint de_refs;
        gchar de_type;
 #define DE_FILE        'f'
 #define DE_DIR 'd'
-       /* Access of anything below this must lock de_file_sema */
-       struct SEMAPHORE *de_file_sema;
+       /* Access of anything below this must lock de_sema */
+       struct SEMAPHORE *de_sema;
+       /* Cached entries have their entire contents in memory or on disk */
+       gboolean de_cached;
+       /* Dirty entires have been changed and not published in GNUnet (implies
+        * cached) */
        gboolean de_dirty;
-       /* de_fi.uri is valid only if de_dirty is not set */
        ECRS_FileInfo de_fi;
-       /* This is valid only if de_dirty is set */
        union
        {
-               /* For directories */
-               GHashTable *de_dir;
-               /* For files */
+               /* For cached directories */
+               GHashTable *de_dir_hash;
+               /* For cached files */
                struct
                {
                        gint de_fd;
@@ -63,11 +70,11 @@
        };
 };
 
-typedef int (*gn_dir_for_each_callback)(struct dirent *de,
-       const gchar *filename, void *data);
+typedef gboolean (*gn_dir_foreach_callback)(struct dirent *de, void *data);
 
 extern struct GC_Configuration *cfg;
 extern struct GE_Context *ectx;
+extern int closing;
 extern unsigned int anonymity;
 extern unsigned int priority;
 extern int uri_files;
@@ -82,13 +89,19 @@
 void gn_dirent_cache_init(void);
 void gn_dirent_cache(struct dirent *de);
 struct dirent *gn_dirent_find(const gchar *path);
-int gn_dirent_upload_locked(struct dirent *de);
+int gn_lock_path(struct dirent *de);
+int gn_unlock_path(struct dirent *de, int dirty);
+#define GN_UNLOCK_CLEAN                        0
+#define GN_UNLOCK_ALL_DIRTY            1
+#define GN_UNLOCK_ANCESTORS_DIRTY      2
 int gn_dirent_download_locked(struct dirent *de);
 
 /* directory.c */
-int gn_directory_for_each(struct dirent *de, gn_dir_for_each_callback cb,
+int gn_directory_foreach(struct dirent *de, gn_dir_foreach_callback cb,
         void *data);
-int gn_directory_insert(struct dirent *de_dir, struct dirent *de_new);
+struct dirent *gn_directory_find(struct dirent *de, const gchar *filename);
+int gn_directory_insert(struct dirent *de, struct dirent *dechild);
+int gn_directory_upload_locked(struct dirent *de);
 
 /* FUSE function files */
 int gn_getattr(const char *path, struct stat *stbuf);
@@ -100,6 +113,7 @@
        struct fuse_file_info *fi);
 int gn_write(const char *path, char *buf, size_t size, off_t offset,
        struct fuse_file_info *fi);
+int gn_release(const char *path, struct fuse_file_info *fi);
 
 /* special_file.c */
 char *gn_dirname(const char *path, char **file);

Modified: gnunet-fuse/main.c
===================================================================
--- gnunet-fuse/main.c  2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/main.c  2007-07-12 06:15:47 UTC (rev 5302)
@@ -36,6 +36,9 @@
 static char *cfgFilename = 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;
 
@@ -74,6 +77,7 @@
        .open = gn_open,
        .read = gn_read,
        .write = gn_write,
+       .release = gn_release,
 };
 
 static struct CommandLineOption gn_options[] =
@@ -205,11 +209,15 @@
        GE_LOG(ectx, GE_BULK | GE_USER | GE_DEBUG, "fuse_main returned\n");
 
        /* Save root uri */
+       closing = 1;
        buf = gn_get_special_file(G_DIR_SEPARATOR_S URI_FILE);
-       ftruncate(root_fd, 0);
-       lseek(root_fd, SEEK_SET, 0);
-       write(root_fd, buf, strlen(buf));
-       FREE(buf);
+       if(buf != NULL)
+       {
+               ftruncate(root_fd, 0);
+               lseek(root_fd, SEEK_SET, 0);
+               write(root_fd, buf, strlen(buf));
+               FREE(buf);
+       }
 out_close_root:
        disk_file_close(ectx, argv[i], root_fd);
 quit:

Modified: gnunet-fuse/mknod.c
===================================================================
--- gnunet-fuse/mknod.c 2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/mknod.c 2007-07-12 06:15:47 UTC (rev 5302)
@@ -28,8 +28,10 @@
 int gn_mknod(const char *path, mode_t mode, dev_t rdev)
 {
        struct dirent *de, *newde;
+       struct ECRS_URI *uri;
        struct ECRS_MetaData *meta;
        char *parent, *file;
+       int ret;
 
        (void)rdev;
        GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n",
@@ -59,19 +61,17 @@
                FREE(parent);
                return -ENOENT;
        }
+       uri = ECRS_stringToUri(ectx, GN_EMPTY_FILE_URI);
        meta = ECRS_createMetaData();
        ECRS_addToMetaData(meta, EXTRACTOR_FILENAME, file);
-       newde = gn_dirent_new(path, NULL, meta, DE_FILE);
+       newde = gn_dirent_new(path, uri, meta, DE_FILE);
        ECRS_freeMetaData(meta);
-       if(gn_directory_insert(de, newde) == -1)
-       {
-               gn_dirent_put(de);
-               gn_dirent_put(newde);
-               FREE(parent);
-               return -EIO;
-       }
+       ECRS_freeUri(uri);
+       ret = gn_directory_insert(de, newde);
        gn_dirent_put(de);
        gn_dirent_put(newde);
        FREE(parent);
+       if(ret == -1)
+               return -EIO;
        return 0;
 }

Modified: gnunet-fuse/read.c
===================================================================
--- gnunet-fuse/read.c  2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/read.c  2007-07-12 06:15:47 UTC (rev 5302)
@@ -119,12 +119,12 @@
                size = -ENOENT;
                goto out;
        }
-       if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
        {
                size = -EIO;
                goto out;
        }
-       if(de->de_dirty)
+       if(de->de_cached)
        {
                slen = pread(de->de_fd, buf, size, offset);
                if(slen == -1)
@@ -155,7 +155,7 @@
                size = -ENODATA;
        }
 out_sema_up:
-       SEMAPHORE_UP(de->de_file_sema);
+       SEMAPHORE_UP(de->de_sema);
 out:
        gn_dirent_put(de);
        return size;

Modified: gnunet-fuse/readdir.c
===================================================================
--- gnunet-fuse/readdir.c       2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/readdir.c       2007-07-12 06:15:47 UTC (rev 5302)
@@ -37,8 +37,7 @@
        const char *prefix;
 };
 
-static int readdir_callback(struct dirent *de, const gchar *filename,
-       void *data)
+static int readdir_callback(struct dirent *de, void *data)
 {
        struct readdir_callback_data *d = data;
 
@@ -46,15 +45,16 @@
 
        if(d->prefix != NULL)
        {
-               char *buf = MALLOC(strlen(d->prefix) + strlen(filename) + 1);
+               char *buf = MALLOC(strlen(d->prefix) + strlen(de->de_basename)
+                       + 1);
 
-               sprintf(buf, "%s%s", d->prefix, filename);
+               sprintf(buf, "%s%s", d->prefix, de->de_basename);
                d->filler(d->buf, buf, NULL, 0);
                FREE(buf);
        }
        else
        {
-               d->filler(d->buf, filename, NULL, 0);
+               d->filler(d->buf, de->de_basename, NULL, 0);
        }
        return OK;
 }
@@ -94,7 +94,7 @@
                d.filler = filler;
                d.buf = buf;
                d.prefix = ".uri.";
-               ret = gn_directory_for_each(de, readdir_callback, &d);
+               ret = gn_directory_foreach(de, readdir_callback, &d);
                if(ret == -1)
                {
                        ret = -ENOENT;
@@ -104,7 +104,7 @@
        d.filler = filler;
        d.buf = buf;
        d.prefix = NULL;
-       ret = gn_directory_for_each(de, readdir_callback, &d);
+       ret = gn_directory_foreach(de, readdir_callback, &d);
        if(ret == -1)
                ret = -ENOENT;
 out:

Added: gnunet-fuse/release.c
===================================================================
--- gnunet-fuse/release.c                               (rev 0)
+++ gnunet-fuse/release.c       2007-07-12 06:15:47 UTC (rev 5302)
@@ -0,0 +1,101 @@
+/*
+ * 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 <unistd.h>
+#include <fuse.h>
+#include "gnfs.h"
+
+static void upcb(guint64 totalBytes, guint64 completedBytes, cron_t eta,
+       void *closure)
+{
+       (void)totalBytes;
+       (void)completedBytes;
+       (void)eta;
+       (void)closure;
+}
+
+static int tt(void *closure)
+{
+       (void)closure;
+
+       return fuse_interrupted() ? SYSERR : OK;
+}
+
+int gn_release(const char *path, struct fuse_file_info *fi)
+{
+       struct dirent *de;
+       struct ECRS_URI *uri;
+       gboolean dirty = GN_UNLOCK_CLEAN;
+
+       (void)fi;
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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)
+       {
+               /* XXX does this get called on directories?? */
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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;
+
+       /* If we're not dirty then we're done */
+       if(!de->de_dirty)
+               goto out;
+
+       /* Take this opportunity */
+       GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG,
+               "%s: uploading file\n", __FUNCTION__);
+       if(ECRS_uploadFile(ectx, cfg, de->de_filename, NO, anonymity, priority,
+               -1, upcb, NULL, tt, NULL, &uri) == SYSERR)
+       {
+               GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR,
+                       "%s: upload failed\n", __FUNCTION__);
+               goto out;
+       }
+       if(de->de_fi.uri != NULL)
+               ECRS_freeUri(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);
+       FREE(de->de_filename);
+
+       /* Now we must mark every containing directory dirty */
+       dirty = GN_UNLOCK_ANCESTORS_DIRTY;
+out:
+       gn_unlock_path(de, dirty);
+       gn_dirent_put(de);
+       return 0;
+}

Modified: gnunet-fuse/special_file.c
===================================================================
--- gnunet-fuse/special_file.c  2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/special_file.c  2007-07-12 06:15:47 UTC (rev 5302)
@@ -90,20 +90,22 @@
                de = gn_dirent_find(parent);
                if(de == NULL)
                        goto out;
-               if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+               if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
                {
                        gn_dirent_put(de);
                        goto out;
                }
                if(de->de_dirty)
                {
-                       /* TODO: publish data here */
-                       SEMAPHORE_UP(de->de_file_sema);
-                       gn_dirent_put(de);
-                       goto out;
+                       if(gn_directory_upload_locked(de) == -1)
+                       {
+                               SEMAPHORE_UP(de->de_sema);
+                               gn_dirent_put(de);
+                               goto out;
+                       }
                }
                buf = ECRS_uriToString(de->de_fi.uri);
-               SEMAPHORE_UP(de->de_file_sema);
+               SEMAPHORE_UP(de->de_sema);
                gn_dirent_put(de);
                buf = REALLOC(buf, strlen(buf) + 2);
                strcat(buf, "\n");
@@ -119,20 +121,34 @@
                FREE(actual_file);
                if(de == NULL)
                        goto out;
-               if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+               if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
                {
                        gn_dirent_put(de);
                        goto out;
                }
                if(de->de_dirty)
                {
-                       /* TODO: publish data here */
-                       SEMAPHORE_UP(de->de_file_sema);
-                       gn_dirent_put(de);
-                       goto out;
+                       if(de->de_type == DE_DIR)
+                       {
+                               if(gn_directory_upload_locked(de) == -1)
+                               {
+                                       SEMAPHORE_UP(de->de_sema);
+                                       gn_dirent_put(de);
+                                       goto out;
+                               }
+                       }
+                       else
+                       {
+                               if(de->de_fi.uri == NULL)
+                               {
+                                       SEMAPHORE_UP(de->de_sema);
+                                       gn_dirent_put(de);
+                                       goto out;
+                               }
+                       }
                }
                buf = ECRS_uriToString(de->de_fi.uri);
-               SEMAPHORE_UP(de->de_file_sema);
+               SEMAPHORE_UP(de->de_sema);
                gn_dirent_put(de);
                buf = REALLOC(buf, strlen(buf) + 2);
                strcat(buf, "\n");

Modified: gnunet-fuse/write.c
===================================================================
--- gnunet-fuse/write.c 2007-07-11 15:07:19 UTC (rev 5301)
+++ gnunet-fuse/write.c 2007-07-12 06:15:47 UTC (rev 5302)
@@ -56,13 +56,13 @@
                goto out;
        }
 
-       /* We must be dirty */
-       if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR)
+       /* We must be cached */
+       if(SEMAPHORE_DOWN(de->de_sema, YES) == SYSERR)
        {
                size = -EIO;
                goto out;
        }
-       if(!de->de_dirty)
+       if(!de->de_cached)
        {
                if(gn_dirent_download_locked(de) == -1)
                {
@@ -77,8 +77,11 @@
                size = -errno;
        else
                size = slen;
+
+       /* Mark us dirty */
+       de->de_dirty = 1;
 out_unlock:
-       SEMAPHORE_UP(de->de_file_sema);
+       SEMAPHORE_UP(de->de_sema);
 out:
        gn_dirent_put(de);
        return size;





reply via email to

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