[Top][All Lists]
[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;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r20414 - gnunet-fuse,
gnunet <=