gnunet-fuse

GNUnet file-sharing directory mounting via FUSE
Log | Files | Refs | Submodules | README | LICENSE

commit 7af3b5fb8574b3fe7b7d138458b13c9501d21b93
parent 0f55c244d04bf49579ef6c4ec2676cf32c0c0b1b
Author: David Barksdale <amatus.amongus@gmail.com>
Date:   Tue, 17 Jul 2007 05:31:52 +0000

Added support for renaming files

Diffstat:
MChangeLog | 2++
MMakefile.am | 1+
Mdirectory.c | 29++++++++++++++---------------
Mdirent.c | 51++++++++++++++++++++++++++++++++++++++++-----------
Mgnfs.h | 10++++++++--
Mmain.c | 1+
Mread.c | 12+-----------
Arename.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwrite.c | 2+-
9 files changed, 203 insertions(+), 40 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,5 @@ +2007-07-17 David Barksdale <amatus@gnu.org> 0.7.2-4 +* Added support for renaming files 2007-07-12 David Barksdale <amatus@gnu.org> 0.7.2-3 * Added support for unlinking files, creating directories, and removing directories diff --git a/Makefile.am b/Makefile.am @@ -10,6 +10,7 @@ gnunet_fs_SOURCES = \ read.c \ readdir.c \ release.c \ + rename.c \ rmdir.c \ special_file.c \ unlink.c \ diff --git a/directory.c b/directory.c @@ -51,7 +51,7 @@ static int dir_cache_cb(const ECRS_FileInfo *fi, const HashCode512 *key, int isRoot, void *data) { struct dirent *de, *deparent = data; - gchar *filename, *newpath, type; + gchar *filename, *path, *newpath, type; size_t len, rlen; (void)key; @@ -78,11 +78,13 @@ static int dir_cache_cb(const ECRS_FileInfo *fi, const HashCode512 *key, type = DE_FILE; /* Create newpath, the path to this entry */ - rlen = strlen(deparent->de_path); + path = gn_dirent_path_get(deparent); + rlen = strlen(path); newpath = MALLOC(rlen + len + 1); - strcpy(newpath, deparent->de_path); - if(deparent->de_path[rlen - 1] != G_DIR_SEPARATOR) + strcpy(newpath, path); + if(path[rlen - 1] != G_DIR_SEPARATOR) strcat(newpath, G_DIR_SEPARATOR_S); + FREE(path); strcat(newpath, filename); /* Create a new dirent for this entry only if one doesn't already exist @@ -100,9 +102,11 @@ static int dir_cache_cb(const ECRS_FileInfo *fi, const HashCode512 *key, } /* Add it to the directory's list (steals our ref)*/ + MUTEX_LOCK(de->de_path_mutex); 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); + MUTEX_UNLOCK(de->de_path_mutex); /* Clean up */ FREE(filename); @@ -117,8 +121,6 @@ static int directory_cache_locked(struct dirent *de) 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, @@ -213,9 +215,6 @@ out: int gn_directory_insert(struct dirent *de, struct dirent *dechild) { - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n", - __FUNCTION__, dechild->de_path); - /* Lock our path */ if(gn_lock_path(de) == -1) return -1; @@ -234,8 +233,10 @@ int gn_directory_insert(struct dirent *de, struct dirent *dechild) } /* If we're already in there, bail out */ + MUTEX_LOCK(dechild->de_path_mutex); if(g_hash_table_lookup(de->de_dir_hash, dechild->de_basename)) { + MUTEX_UNLOCK(dechild->de_path_mutex); gn_unlock_path(de, GN_UNLOCK_CLEAN); return -1; } @@ -243,6 +244,7 @@ int gn_directory_insert(struct dirent *de, struct dirent *dechild) /* Insert the child in our de_dir_hash */ gn_dirent_ref(dechild); g_hash_table_replace(de->de_dir_hash, dechild->de_basename, dechild); + MUTEX_UNLOCK(dechild->de_path_mutex); /* Cache the dirent */ gn_dirent_cache_insert(dechild); @@ -254,9 +256,6 @@ int gn_directory_insert(struct dirent *de, struct dirent *dechild) int gn_directory_remove(struct dirent *de, struct dirent *dechild) { - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n", - __FUNCTION__, dechild->de_path); - /* Lock our path */ if(gn_lock_path(de) == -1) return -1; @@ -274,13 +273,16 @@ int gn_directory_remove(struct dirent *de, struct dirent *dechild) } /* Remove from dir_hash */ + MUTEX_LOCK(dechild->de_path_mutex); if(!g_hash_table_remove(de->de_dir_hash, dechild->de_basename)) { + MUTEX_UNLOCK(dechild->de_path_mutex); GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR, "%s: not found in dir_hash\n", __FUNCTION__); goto out_err; } + MUTEX_UNLOCK(dechild->de_path_mutex); /* Remove from dirent cache */ gn_dirent_cache_remove(dechild); @@ -359,9 +361,6 @@ int gn_directory_upload_locked(struct dirent *de) 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; diff --git a/dirent.c b/dirent.c @@ -66,8 +66,9 @@ void gn_dirent_put(struct dirent *de) return; } MUTEX_UNLOCK(de->de_refs_mutex); - MUTEX_DESTROY(de->de_refs_mutex); + MUTEX_DESTROY(de->de_path_mutex); FREE(de->de_path); + MUTEX_DESTROY(de->de_refs_mutex); SEMAPHORE_DESTROY(de->de_sema); if(de->de_fi.uri != NULL) ECRS_freeUri(de->de_fi.uri); @@ -92,6 +93,28 @@ void gn_dirent_put(struct dirent *de) FREE(de); } +char *gn_dirent_path_get(struct dirent *de) +{ + char *ret; + + MUTEX_LOCK(de->de_path_mutex); + ret = STRDUP(de->de_path); + 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) +{ + MUTEX_LOCK(de->de_path_mutex); + FREE(de->de_path); + de->de_path = STRDUP(path); + de->de_basename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1; + 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, @@ -108,6 +131,7 @@ struct dirent *gn_dirent_new(const gchar *path, struct ECRS_URI *uri, struct dirent *de; de = MALLOC(sizeof(*de)); + de->de_path_mutex = MUTEX_CREATE(0); de->de_path = STRDUP(path); de->de_basename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1; de->de_refs_mutex = MUTEX_CREATE(0); @@ -155,8 +179,10 @@ void gn_dirent_cache_insert(struct dirent *de) * XXX: But what about diry entries?? */ if(SEMAPHORE_DOWN(path_sema, YES) == SYSERR) return; + MUTEX_LOCK(de->de_path_mutex); GE_ASSERT(ectx, !g_hash_table_lookup(path_hash, de->de_path)); g_hash_table_replace(path_hash, de->de_path, de); + MUTEX_UNLOCK(de->de_path_mutex); gn_dirent_ref(de); SEMAPHORE_UP(path_sema); } @@ -168,7 +194,10 @@ void gn_dirent_cache_remove(struct dirent *de) { if(SEMAPHORE_DOWN(path_sema, YES) == SYSERR) return; + /* This is safe because we still hold a ref */ + MUTEX_LOCK(de->de_path_mutex); g_hash_table_remove(path_hash, de->de_path); + MUTEX_UNLOCK(de->de_path_mutex); SEMAPHORE_UP(path_sema); } @@ -222,9 +251,6 @@ int gn_path_foreach(const gchar *path, gn_dir_foreach_callback cb, void *data) /* If we found it then continue */ if(next_de != NULL) { - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "%s: found in cache '%s'\n", __FUNCTION__, - next_de->de_path); gn_dirent_put(de); de = next_de; continue; @@ -240,9 +266,6 @@ int gn_path_foreach(const gchar *path, gn_dir_foreach_callback cb, void *data) de = NULL; break; } - 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); @@ -303,9 +326,12 @@ static gboolean lock_path_callback(struct dirent *de, void *data) int gn_lock_path(struct dirent *de) { struct dirent *detmp = NULL; + char *path; - if(gn_path_foreach(de->de_path, lock_path_callback, &detmp) == -1) + path = gn_dirent_path_get(de); + if(gn_path_foreach(path, lock_path_callback, &detmp) == -1) { + FREE(path); GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR, "%s: failed!\n", __FUNCTION__); /* Back out all the locks we aquired */ @@ -313,6 +339,7 @@ int gn_lock_path(struct dirent *de) gn_unlock_path(detmp, GN_UNLOCK_CLEAN); return -1; } + FREE(path); return 0; } @@ -341,15 +368,19 @@ static gboolean unlock_path_callback(struct dirent *de, void *data) int gn_unlock_path(struct dirent *de, int dirty) { struct unlock_path_data d; + char *path; d.dirty = dirty; d.de = de; - if(gn_path_foreach(de->de_path, unlock_path_callback, &d) == -1) + path = gn_dirent_path_get(de); + if(gn_path_foreach(path, unlock_path_callback, &d) == -1) { + FREE(path); GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_ERROR, "%s: failed!\n", __FUNCTION__); return -1; } + FREE(path); return 0; } @@ -380,8 +411,6 @@ int gn_dirent_download_locked(struct dirent *de) { char filename[] = GN_MKSTEMP_FILE; - 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; diff --git a/gnfs.h b/gnfs.h @@ -42,14 +42,17 @@ struct dirent { + /* de_path_mutex protects de_path and de_basename */ + struct MUTEX *de_path_mutex; gchar *de_path; gchar *de_basename; + /* de_refs_mutex protects de_refs */ 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_sema */ + /* de_sema protects everything below */ struct SEMAPHORE *de_sema; /* Cached entries have their entire contents in memory or on disk */ gboolean de_cached; @@ -86,6 +89,8 @@ struct dirent *gn_dirent_new(const gchar *path, struct ECRS_URI *uri, struct dirent *gn_dirent_get(const gchar *path); void gn_dirent_ref(struct dirent *de); void gn_dirent_put(struct dirent *de); +char *gn_dirent_path_get(struct dirent *de); +void gn_dirent_path_set(struct dirent *de, const char *path); void gn_dirent_cache_init(void); void gn_dirent_cache_insert(struct dirent *de); void gn_dirent_cache_remove(struct dirent *de); @@ -113,11 +118,12 @@ int gn_mknod(const char *path, mode_t mode, dev_t rdev); int gn_mkdir(const char *path, mode_t mode); int gn_unlink(const char *path); int gn_rmdir(const char *path); +int gn_rename(const char *from, const char *to); int gn_utimens(const char *path, const struct timespec ts[2]); int gn_open(const char *path, struct fuse_file_info *fi); int gn_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); -int gn_write(const char *path, char *buf, size_t size, off_t offset, +int gn_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi); int gn_release(const char *path, struct fuse_file_info *fi); diff --git a/main.c b/main.c @@ -77,6 +77,7 @@ static struct fuse_operations fops = .mkdir = gn_mkdir, .unlink = gn_unlink, .rmdir = gn_rmdir, + .rename = gn_rename, .utimens = gn_utimens, .open = gn_open, .read = gn_read, diff --git a/read.c b/read.c @@ -45,14 +45,10 @@ static void dpcb(unsigned long long totalBytes, (void)completedBytes; (void)eta; - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "%s: lastBlockOffset %llu lastBlockSize %d\n", __FUNCTION__, - lastBlockOffset, lastBlockSize); - /* 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; @@ -156,14 +152,8 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, d.buf = buf; d.size = size; d.offset = offset; - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "%s: calling ECRS_downloadPartialFile %u bytes %lld offset\n", - __FUNCTION__, size, offset); ret = ECRS_downloadPartialFile(ectx, cfg, de->de_fi.uri, "/dev/null", offset, size, anonymity, YES, dpcb, &d, tt, NULL); - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "%s: ECRS_downloadPartialFile returned %d\n", - __FUNCTION__, ret); if(ret != OK) { GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR, diff --git a/rename.c b/rename.c @@ -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; + + GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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); + 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); + GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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); + 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; + } + GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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); + GE_LOG(ectx, GE_BULK | GE_DEVELOPER | 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; +} diff --git a/write.c b/write.c @@ -25,7 +25,7 @@ #include <fuse.h> #include "gnfs.h" -int gn_write(const char *path, char *buf, size_t size, off_t offset, +int gn_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { struct dirent *de;