gnunet-fuse

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

commit 0805e6ac4bcb1e41f810f6d4963ecb746a6a3aca
parent 1e0aa8294b45c6876a37447223d13c92a66cb11e
Author: David Barksdale <amatus.amongus@gmail.com>
Date:   Tue, 26 Jun 2007 05:11:52 +0000

Beginnings of write support

Diffstat:
MREADME | 10++++------
Mdirectory.c | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mdirent.c | 248++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mgetattr.c | 36+++++++++++++++++++++++++++++-------
Mgnfs.h | 30++++++++++++++++++++++++------
Mmain.c | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mopen.c | 15+++++----------
Mread.c | 28+++++++++++++++++++++++-----
Mreaddir.c | 7+------
Mspecial_file.c | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
10 files changed, 537 insertions(+), 135 deletions(-)

diff --git a/README b/README @@ -1,28 +1,26 @@ gnunet-fuse - FUSE filesystem for GNUnet -NOTE: Currently only read-only mounting is supported. - Summary ======= You need the URI of a file with the mime-type of application/gnunet-directory. You can either publish a directory with gnunet-insert or do a search for the mime-type. To mount the URI use the following command. -$ gnunet-fs gnunet://ecrs/chk/XXXX/YYYY.NNNN /mnt +$ echo gnunet://ecrs/chk/XXXX/YYYY.NNNN > uri_file +$ gnunet-fs uri_file /mnt Where gnunet://ecrs/chk/XXXX/YYYY.NNNN is the URI and /mnt is the mount point. -I suggest you store your URIs one each to a file and use `cat uri` in place of -the URI in the example above. Usage ===== -gnunet-fuse [OPTIONS] <URI> <PATH> +gnunet-fuse [OPTIONS] <URI FILE> <PATH> Arguments mandatory for long options are also mandatory for short options. -h, --help print this help -c, --config=FILENAME use configuration file FILENAME -L, --log=LOGLEVEL configure logging to use LOGLEVEL -l, --logfile=FILE set logfile name -a, --anonymity=LEVEL set the desired LEVEL of sender-anonymity + -p, --priority=LEVEL set the desired LEVEL of priority -u, --uri-files Make .uri files visible -x, --Xfuse Escape fuse option diff --git a/directory.c b/directory.c @@ -59,9 +59,11 @@ static int dir_for_each_cb(const ECRS_FileInfo *fi, const HashCode512 *key, size_t len, rlen; int ret; + (void)key; + if(isRoot == YES) - return d->cb(d->de, NULL, fi, key, isRoot, d->data); - + return OK; + /* Figure out the filename and type from metadata */ filename = ECRS_getFromMetaData(fi->meta, EXTRACTOR_FILENAME); if(filename == NULL) @@ -79,7 +81,7 @@ static int dir_for_each_cb(const ECRS_FileInfo *fi, const HashCode512 *key, } else type = DE_FILE; - + /* Create newpath, the path to this entry */ rlen = strlen(d->de->de_path); newpath = MALLOC(rlen + len + 1); @@ -89,13 +91,13 @@ static int dir_for_each_cb(const ECRS_FileInfo *fi, const HashCode512 *key, strcat(newpath, filename); /* Create a new dirent for this entry */ - de = gn_dirent_new(newpath, fi->uri, type); + de = gn_dirent_new(newpath, fi->uri, fi->meta, type); /* Add it to the cache */ gn_dirent_cache(de); /* Call the callback function */ - ret = d->cb(de, filename, fi, key, isRoot, d->data); + ret = d->cb(de, filename, d->data); /* Clean up */ gn_dirent_put(de); @@ -104,6 +106,21 @@ static int dir_for_each_cb(const ECRS_FileInfo *fi, const HashCode512 *key, return ret; } +static gboolean hash_foreach_cb(gpointer key, gpointer value, gpointer data) +{ + struct dir_for_each_data *d = data; + struct dirent *de = value; + char *filename = strrchr(de->de_path, G_DIR_SEPARATOR) + 1; + int ret; + + (void)key; + + gn_dirent_ref(de); + ret = d->cb(de, filename, d->data); + gn_dirent_put(de); + return ret == SYSERR; +} + int gn_directory_for_each(struct dirent *de, gn_dir_for_each_callback cb, void *data) { @@ -113,22 +130,86 @@ int gn_directory_for_each(struct dirent *de, gn_dir_for_each_callback cb, int ret; guint64 len; - len = ECRS_fileSize(de->de_uri); + 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) + return -1; + if(de->de_dirty) + { + g_hash_table_find(de->de_dir, hash_foreach_cb, &d); + SEMAPHORE_UP(de->de_file_sema); + return 0; + } + len = ECRS_fileSize(de->de_fi.uri); mem = MALLOC(len); - ret = ECRS_downloadPartialFile(ectx, cfg, de->de_uri, "/dev/null", + 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) { GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR, "%s: failed to download directory\n", __FUNCTION__); - goto err_out; + ret = -1; + goto out; } - d.cb = cb; - d.data = data; - d.de = de; ECRS_listDirectory(ectx, mem, len, &md, dir_for_each_cb, &d); - return 0; -err_out: + ECRS_freeMetaData(md); + ret = 0; +out: FREE(mem); - return -1; + return ret; +} + +static int directory_insert_callback(struct dirent *de, const gchar *filename, + void *data) +{ + struct dir_for_each_data *d = data; + + (void)filename; + gn_dirent_ref(de); + g_hash_table_replace(d->de->de_dir, de->de_path, de); + return OK; +} + +int gn_directory_insert(struct dirent *de_dir, struct dirent *de_new) +{ + struct dir_for_each_data d; + void *mem; + guint64 len; + int ret = 0; + struct ECRS_MetaData *md; + + if(SEMAPHORE_DOWN(de_dir->de_file_sema, YES) == SYSERR) + return -1; + if(!de_dir->de_dirty) + { + 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) + { + GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR, + "%s: failed to download directory\n", + __FUNCTION__); + ret = -1; + goto out; + } + ECRS_listDirectory(ectx, mem, len, &md, dir_for_each_cb, &d); + ECRS_freeMetaData(md); + } + gn_dirent_ref(de_new); + g_hash_table_replace(de_dir->de_dir, de_new->de_path, de_new); +out: + SEMAPHORE_UP(de_dir->de_file_sema); + return ret; } diff --git a/dirent.c b/dirent.c @@ -18,27 +18,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <unistd.h> #include <glib.h> #include <string.h> #include "gnfs.h" GHashTable *path_hash; -struct MUTEX *path_mutex; +struct SEMAPHORE *path_sema; /* - * Create a new dirent with a reference, path and uri are copied + * Reference a dirent, call gn_dirent_put when finished */ -struct dirent *gn_dirent_new(const gchar *path, struct ECRS_URI *uri, - gchar type) +void gn_dirent_ref(struct dirent *de) { - struct dirent *de; - - de = MALLOC(sizeof(*de)); - de->de_path = STRDUP(path); - de->de_uri = ECRS_dupUri(uri); - de->de_type = type; - de->de_refs = 1; - return de; + MUTEX_LOCK(de->de_mutex); + de->de_refs++; + MUTEX_UNLOCK(de->de_mutex); } /* @@ -48,52 +43,96 @@ struct dirent *gn_dirent_get(const gchar *path) { struct dirent *de; - MUTEX_LOCK(path_mutex); + if(SEMAPHORE_DOWN(path_sema, YES) == SYSERR) + return NULL; de = g_hash_table_lookup(path_hash, path); if(de != NULL) - de->de_refs++; - MUTEX_UNLOCK(path_mutex); + gn_dirent_ref(de); + SEMAPHORE_UP(path_sema); return de; } /* - * Reference a dirent, call gn_dirent_put when finished + * Release a reference to a dirent */ -void gn_dirent_ref(struct dirent *de) -{ - MUTEX_LOCK(path_mutex); - de->de_refs++; - MUTEX_UNLOCK(path_mutex); -} - -static void dirent_destroy(gpointer data) +void gn_dirent_put(struct dirent *de) { - struct dirent *de = data; - + MUTEX_LOCK(de->de_mutex); de->de_refs--; if(de->de_refs < 1) { + MUTEX_UNLOCK(de->de_mutex); + MUTEX_DESTROY(de->de_mutex); FREE(de->de_path); - ECRS_freeUri(de->de_uri); + 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) + { + 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); + } + } FREE(de); + return; } + MUTEX_UNLOCK(de->de_mutex); } -/* - * Release a reference to a dirent - */ -void gn_dirent_put(struct dirent *de) +void gn_dirent_cache_init(void) { - MUTEX_LOCK(path_mutex); - dirent_destroy(de); - MUTEX_UNLOCK(path_mutex); + path_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + (GDestroyNotify)gn_dirent_put); + path_sema = SEMAPHORE_CREATE(1); } -void gn_dirent_cache_init(void) +/* + * Create a new dirent with a reference, path and uri are copied + */ +struct dirent *gn_dirent_new(const gchar *path, struct ECRS_URI *uri, + struct ECRS_MetaData *meta, gchar type) { - path_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, - dirent_destroy); - path_mutex = MUTEX_CREATE(0); + struct dirent *de; + + de = MALLOC(sizeof(*de)); + de->de_path = STRDUP(path); + de->de_mutex = MUTEX_CREATE(0); + de->de_refs = 1; + de->de_type = type; + de->de_file_sema = SEMAPHORE_CREATE(1); + if(uri != NULL) + { + de->de_fi.uri = ECRS_dupUri(uri); + de->de_dirty = 0; + } + else + { + de->de_dirty = 1; + if(type == DE_FILE) + { + char filename[] = "/tmp/gnfsXXXXXX"; + + de->de_fd = mkstemp(filename); + de->de_filename = STRDUP(filename); + } + else + { + de->de_dir = g_hash_table_new_full(g_str_hash, + g_str_equal, NULL, + (GDestroyNotify)gn_dirent_put); + } + } + de->de_fi.meta = ECRS_dupMetaData(meta); + return de; } /* @@ -101,18 +140,15 @@ void gn_dirent_cache_init(void) */ void gn_dirent_cache(struct dirent *de) { - gchar *uristr; - - uristr = ECRS_uriToString(de->de_uri); GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "%s: name '%s' uri '%s'\n", __FUNCTION__, de->de_path, uristr); - FREE(uristr); + "%s: path '%s'\n", __FUNCTION__, de->de_path); /* TODO: Here we need to see if the cache has gotten too big and empty * it */ - MUTEX_LOCK(path_mutex); - de->de_refs++; + gn_dirent_ref(de); + if(SEMAPHORE_DOWN(path_sema, YES) == SYSERR) + return; g_hash_table_replace(path_hash, de->de_path, de); - MUTEX_UNLOCK(path_mutex); + SEMAPHORE_UP(path_sema); } struct dirent_find_data @@ -123,14 +159,11 @@ struct dirent_find_data }; static gboolean dirent_find(struct dirent *de, const gchar *filename, - const ECRS_FileInfo *fi, const HashCode512 *key, int isRoot, void *data) + void *data) { struct dirent_find_data *dfd = data; - (void)fi; - (void)key; - - if(isRoot == YES || dfd->found == 1 || strcmp(filename, dfd->name) != 0) + if(dfd->found == 1 || strcmp(filename, dfd->name) != 0) return OK; dfd->found = 1; @@ -150,12 +183,10 @@ struct dirent *gn_dirent_find(const gchar *path) struct dirent_find_data dfd; /* Start de off at the root */ - MUTEX_LOCK(root_mutex); de = root_de; gn_dirent_ref(de); - MUTEX_UNLOCK(root_mutex); - /* Root shortcut before we grab path_mutex */ + /* Root shortcut */ if(strcmp(path, G_DIR_SEPARATOR_S) == 0) return de; @@ -226,3 +257,112 @@ struct dirent *gn_dirent_find(const gchar *path) return de; } + +struct upload_data +{ + int count; + ECRS_FileInfo *fis; +}; + +int dirent_upload_locked(struct dirent *de); + +void upload_foreach(gpointer key, gpointer value, gpointer data) +{ + struct dirent *de = value; + struct upload_data *d = data; + + (void)key; + + if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR) + return; + if(de->de_dirty) + { + if(de->de_type == DE_FILE) + { + if(de->de_fi.uri == NULL) + goto out; + } + else + { + dirent_upload_locked(de); + } + } + d->count++; + d->fis = REALLOC(d->fis, d->count * sizeof(*d->fis)); + d->fis[d->count - 1].uri = ECRS_dupUri(de->de_fi.uri); + d->fis[d->count - 1].meta = ECRS_dupMetaData(de->de_fi.meta); +out: + SEMAPHORE_UP(de->de_file_sema); +} + +void upcb(guint64 totalBytes, guint64 completedBytes, cron_t eta, + void *closure) +{ + (void)totalBytes; + (void)completedBytes; + (void)eta; + (void)closure; +} + +int tt(void *closure) +{ + (void)closure; + + return fuse_interrupted() ? SYSERR : OK; +} + +int dirent_upload_locked(struct dirent *de) +{ + int i, fd; + struct upload_data d; + char *buf, filename[] = "/tmp/gnfsXXXXXX"; + guint64 len; + struct ECRS_URI *uri; + + if(!de->de_dirty) + return 0; + d.count = 0; + d.fis = NULL; + g_hash_table_foreach(de->de_dir, upload_foreach, &d); + if(ECRS_createDirectory(ectx, &buf, &len, d.count, d.fis, + de->de_fi.meta) == SYSERR) + goto out; + fd = mkstemp(filename); + if(fd == -1) + goto out; + write(fd, buf, len); + close(fd); + if(ECRS_uploadFile(ectx, cfg, filename, NO, anonymity, priority, + -1, upcb, NULL, tt, NULL, &uri) == SYSERR) + goto out_unlink_file; + 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; +out_unlink_file: + unlink(filename); +out: + for(i = 0; i < d.count; i++) + { + ECRS_freeUri(d.fis[i].uri); + ECRS_freeMetaData(d.fis[i].meta); + } + FREE(d.fis); + 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 + */ +int gn_dirent_upload(struct dirent *de) +{ + int ret; + + if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR) + return -1; + ret = dirent_upload_locked(de); + SEMAPHORE_UP(de->de_file_sema); + return ret; +} diff --git a/getattr.c b/getattr.c @@ -28,33 +28,55 @@ int gn_getattr(const char *path, struct stat *stbuf) { struct dirent *de; - char *special; + guint64 size = 0; GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "getattr for '%s'\n", path); /* Check to see if this is a special file */ - special = gn_get_special_file(path); - if(special != NULL) + if(gn_exists_special_file(path)) { memset(stbuf, 0, sizeof(*stbuf)); stbuf->st_mode = 0555 | S_IFREG; stbuf->st_nlink = 1; - stbuf->st_size = strlen(special); - FREE(special); + stbuf->st_size = 0; return 0; } /* Fill in dirent stat info */ de = gn_dirent_find(path); if(de == NULL) + { + GE_LOG(ectx, GE_BULK | GE_USER | GE_ERROR, + "%s: could not find path '%s'\n", __FUNCTION__, path); return -ENOENT; + } memset(stbuf, 0, sizeof(*stbuf)); - stbuf->st_mode = 0555; + stbuf->st_mode = 0777; stbuf->st_mode |= de->de_type == DE_DIR ? S_IFDIR : S_IFREG; stbuf->st_nlink = 1; - stbuf->st_size = ECRS_fileSize(de->de_uri); + if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR) + return -ENOENT; + if(de->de_dirty) + { + if(de->de_type == DE_FILE && disk_file_size(ectx, + de->de_filename, &size, NO) == SYSERR) + { + 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); + gn_dirent_put(de); + return -ENOENT; + } + } + else + { + size = ECRS_fileSize(de->de_fi.uri); + } + SEMAPHORE_UP(de->de_file_sema); gn_dirent_put(de); + stbuf->st_size = size; return 0; } diff --git a/gnfs.h b/gnfs.h @@ -38,27 +38,43 @@ struct dirent { gchar *de_path; - struct ECRS_URI *de_uri; + struct MUTEX *de_mutex; + gint de_refs; gchar de_type; #define DE_FILE 'f' #define DE_DIR 'd' - gint de_refs; + /* Access of anything below this must lock de_file_sema */ + struct SEMAPHORE *de_file_sema; + 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 */ + struct + { + gint de_fd; + gchar *de_filename; + }; + }; }; typedef int (*gn_dir_for_each_callback)(struct dirent *de, - const gchar *filename, const ECRS_FileInfo *fi, const HashCode512 *key, - int isRoot, void *data); + const gchar *filename, void *data); extern struct GC_Configuration *cfg; extern struct GE_Context *ectx; extern unsigned int anonymity; +extern unsigned int priority; extern int uri_files; extern struct dirent *root_de; -extern struct MUTEX *root_mutex; /* dirent.c */ struct dirent *gn_dirent_new(const gchar *path, struct ECRS_URI *uri, - gchar type); + struct ECRS_MetaData *meta, gchar type); struct dirent *gn_dirent_get(const gchar *path); void gn_dirent_ref(struct dirent *de); void gn_dirent_put(struct dirent *de); @@ -69,6 +85,7 @@ struct dirent *gn_dirent_find(const gchar *path); /* directory.c */ int gn_directory_for_each(struct dirent *de, gn_dir_for_each_callback cb, void *data); +int gn_directory_insert(struct dirent *de_dir, struct dirent *de_new); /* FUSE function files */ int gn_getattr(const char *path, struct stat *stbuf); @@ -79,6 +96,7 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); /* special_file.c */ +int gn_exists_special_file(const char *path); char *gn_get_special_file(const char *path); #endif /* _GNFS_H_ */ diff --git a/main.c b/main.c @@ -20,6 +20,7 @@ #include <stdio.h> #include <string.h> +#include <unistd.h> #include <glib.h> #include <fuse.h> #include <GNUnet/gnunet_directories.h> @@ -33,14 +34,23 @@ struct GC_Configuration *cfg; struct GE_Context *ectx; static char *cfgFilename = DEFAULT_CLIENT_CONFIG_FILE; static char *cfgLogfile = "/tmp/gnunet_fuse.log"; + +/* 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; -struct MUTEX *root_mutex; int getopt_configure_argv(CommandLineProcessorContext *ctx, void *scls, const char *cmdLineOption, const char *value) @@ -74,6 +84,9 @@ static struct CommandLineOption gn_options[] = { '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, @@ -85,17 +98,17 @@ int main(int argc, char **argv) { int i, ret; struct ECRS_URI *uri; + char *buf; - /* Initialize fuse options to specify a read-only filesystem (for now)*/ - fuse_argc = 3; + /* Initialize fuse options */ + fuse_argc = 1; fuse_argv = MALLOC(sizeof(char *) * (fuse_argc + 1)); fuse_argv[0] = argv[0]; - fuse_argv[1] = "-o"; - fuse_argv[2] = "ro"; - fuse_argv[3] = NULL; + fuse_argv[1] = NULL; /* Parse gnunet options */ - i = GNUNET_init(argc, argv, "gnunet-fuse [OPTIONS] <URI> <PATH>", + i = GNUNET_init(argc, argv, + "gnunet-fuse [OPTIONS] <URI FILE> <MOUNT-POINT>", &cfgFilename, gn_options, &ectx, &cfg); if(i == -1) { @@ -117,17 +130,67 @@ int main(int argc, char **argv) } /* Set URI as our root directory entry */ - uri = ECRS_stringToUri(ectx, argv[i]); - if(uri == NULL || !ECRS_isFileUri(uri)) + gn_dirent_cache_init(); + if(disk_file_test(ectx, argv[i]) == YES) { - printf("URI '%s' cannot be mounted\n", argv[i]); - ret = -1; - goto quit; + guint64 len; + char *uribuf; + + root_fd = 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(disk_file_size(ectx, argv[i], &len, YES) == SYSERR) + { + printf("Unable to determine URI file size\n"); + ret = -1; + goto out_close_root; + } + uribuf = MALLOC(len + 1); + read(root_fd, uribuf, len); + uribuf[len] = '\0'; + uri = ECRS_stringToUri(ectx, uribuf); + FREE(uribuf); + if(uri == NULL) + { + printf("URI cannot be parsed\n"); + ret = -1; + goto out_close_root; + } + if(!ECRS_isFileUri(uri)) + { + struct ECRS_URI *new_uri; + + new_uri = ECRS_getContentUri(uri); + if(new_uri == NULL) + { + printf("URI cannot be mounted\n"); + ret = -1; + goto out_close_root; + } + ECRS_freeUri(uri); + uri = new_uri; + } + root_de = gn_dirent_new(G_DIR_SEPARATOR_S, uri, NULL, DE_DIR); + ECRS_freeUri(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 = 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); } - gn_dirent_cache_init(); - root_de = gn_dirent_new(G_DIR_SEPARATOR_S, uri, DE_DIR); - ECRS_freeUri(uri); - root_mutex = MUTEX_CREATE(0); /* Add mount point as the last fuse option */ fuse_argv = REALLOC(fuse_argv, sizeof(char *) * (fuse_argc + 2)); @@ -137,6 +200,15 @@ int main(int argc, char **argv) GE_LOG(ectx, GE_BULK | GE_USER | GE_DEBUG, "calling fuse_main\n"); ret = fuse_main(fuse_argc, fuse_argv, &fops, NULL); + GE_LOG(ectx, GE_BULK | GE_USER | GE_DEBUG, "fuse_main returned\n"); + + /* Save root uri */ + buf = gn_get_special_file(G_DIR_SEPARATOR_S URI_FILE); + ftruncate(root_fd, 0); + write(root_fd, buf, strlen(buf)); + FREE(buf); +out_close_root: + disk_file_close(ectx, argv[i], root_fd); quit: FREE(fuse_argv); GNUNET_fini(ectx, cfg); diff --git a/open.c b/open.c @@ -27,31 +27,26 @@ int gn_open(const char *path, struct fuse_file_info *fi) { struct dirent *de; - char *special; (void)fi; - GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "open for '%s'\n", - path); + GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, "%s: for '%s'\n", + __FUNCTION__, path); /* Check for special file */ - special = gn_get_special_file(path); - if(special != NULL) - { - FREE(special); + if(gn_exists_special_file(path)) return 0; - } de = gn_dirent_find(path); if(de == NULL) { GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "open: file not found\n"); + "%s: file not found\n", __FUNCTION__); return -ENOENT; } if(de->de_type != DE_FILE) { GE_LOG(ectx, GE_BULK | GE_DEVELOPER | GE_DEBUG, - "open: not a file\n"); + "%s: not a file\n", __FUNCTION__); gn_dirent_put(de); return -ENOENT; } diff --git a/read.c b/read.c @@ -18,10 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <fuse.h> +#define _XOPEN_SOURCE 500 #include <string.h> #include <errno.h> #include <unistd.h> +#include <fuse.h> #include "gnfs.h" struct read_data @@ -75,7 +76,8 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, struct dirent *de; struct read_data d; char *special; - int ret, slen; + int ret; + ssize_t slen; guint64 len; (void)fi; @@ -117,11 +119,25 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, size = -ENOENT; goto out; } - len = ECRS_fileSize(de->de_uri); + if(SEMAPHORE_DOWN(de->de_file_sema, YES) == SYSERR) + { + size = -EINTR; + goto out; + } + if(de->de_dirty) + { + slen = pread(de->de_fd, buf, size, offset); + if(slen == -1) + size = -errno; + else + size = slen; + goto out_sema_up; + } + len = ECRS_fileSize(de->de_fi.uri); if((guint64)offset >= len) { size = 0; - goto out; + goto out_sema_up; } if((guint64)offset + size > len) { @@ -130,7 +146,7 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, d.buf = buf; d.size = size; d.offset = offset; - ret = ECRS_downloadPartialFile(ectx, cfg, de->de_uri, "/dev/null", + ret = ECRS_downloadPartialFile(ectx, cfg, de->de_fi.uri, "/dev/null", anonymity, offset, size, YES, dpcb, &d, tt, NULL); if(ret != OK) { @@ -138,6 +154,8 @@ int gn_read(const char *path, char *buf, size_t size, off_t offset, "%s: failed to download directory\n", __FUNCTION__); size = -ENODATA; } +out_sema_up: + SEMAPHORE_UP(de->de_file_sema); out: gn_dirent_put(de); return size; diff --git a/readdir.c b/readdir.c @@ -38,16 +38,11 @@ struct readdir_callback_data }; static int readdir_callback(struct dirent *de, const gchar *filename, - const ECRS_FileInfo *fi, const HashCode512 *key, int isRoot, void *data) + void *data) { struct readdir_callback_data *d = data; (void)de; - (void)fi; - (void)key; - - if(isRoot) - return OK; if(d->prefix != NULL) { diff --git a/special_file.c b/special_file.c @@ -23,6 +23,49 @@ #include <GNUnet/gnunet_ecrs_lib.h> #include "gnfs.h" +/* 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; + + /* Break path into parent and file (dirname and basename kinda) */ + parent = STRDUP(path); + file = strrchr(parent, G_DIR_SEPARATOR); + if(file == NULL) + goto out; + file[0] = '\0'; + 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 = 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); + FREE(actual_file); + if(de == NULL) + goto out; + gn_dirent_put(de); + ret = 1; + } +out: + 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; @@ -39,22 +82,31 @@ char *gn_get_special_file(const char *path) /* Check for special file name */ if(strcmp(file, URI_FILE) == 0) { - char *uri; - /* Return URI of the 'current' directory */ de = gn_dirent_find(parent); if(de == NULL) goto out; - uri = ECRS_uriToString(de->de_uri); + if(SEMAPHORE_DOWN(de->de_file_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; + } + buf = ECRS_uriToString(de->de_fi.uri); + SEMAPHORE_UP(de->de_file_sema); gn_dirent_put(de); - buf = MALLOC(strlen(uri) + 2); - strcpy(buf, uri); - FREE(uri); + buf = REALLOC(buf, strlen(buf) + 2); strcat(buf, "\n"); } else if(strncmp(file, URI_FILE ".", URI_LEN + 1) == 0) { - char *uri, *actual_file = MALLOC(strlen(path)); + char *actual_file = MALLOC(strlen(path)); /* Return URI of the file named after the .uri. */ sprintf(actual_file, "%s" G_DIR_SEPARATOR_S "%s", parent, @@ -63,11 +115,22 @@ char *gn_get_special_file(const char *path) FREE(actual_file); if(de == NULL) goto out; - uri = ECRS_uriToString(de->de_uri); + if(SEMAPHORE_DOWN(de->de_file_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; + } + buf = ECRS_uriToString(de->de_fi.uri); + SEMAPHORE_UP(de->de_file_sema); gn_dirent_put(de); - buf = MALLOC(strlen(uri) + 2); - strcpy(buf, uri); - FREE(uri); + buf = REALLOC(buf, strlen(buf) + 2); strcat(buf, "\n"); } out: