gnunet-fuse

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

commit c2327e49d957b9579de5b2cf8c51027df8eedaac
parent c2b14e3b8c3dbf84636266abb0bd5cc63ecf7ced
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  4 Jun 2012 13:03:36 +0000

-towards downloading files

Diffstat:
Msrc/fuse/Makefile.am | 3++-
Asrc/fuse/gfs_download.c | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/fuse/gfs_download.h | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/fuse/gnunet-fuse.c | 16+++++++++++++---
Msrc/fuse/gnunet-fuse.h | 16++++++++++++++++
Msrc/fuse/readdir.c | 225+++++++------------------------------------------------------------------------
6 files changed, 315 insertions(+), 211 deletions(-)

diff --git a/src/fuse/Makefile.am b/src/fuse/Makefile.am @@ -10,7 +10,9 @@ bin_PROGRAMS = gnunet-fuse gnunet_fuse_SOURCES = \ gnunet-fuse.c \ + gfs_download.c gfs_download.h \ mutex.c mutex.h \ + readdir.c \ mkdir.c \ mknod.c \ release.c \ @@ -20,7 +22,6 @@ gnunet_fuse_SOURCES = \ unlink.c \ utimens.c \ write.c \ - readdir.c \ read.c \ open.c \ getattr.c diff --git a/src/fuse/gfs_download.c b/src/fuse/gfs_download.c @@ -0,0 +1,223 @@ +/* + This file is part of gnunet-fuse. + (C) 2012 Christian Grothoff (and other contributing authors) + + gnunet-fuse is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + 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 + +*/ +/** + * @file fuse/gfs_download.h + * @brief download files using FS + * @author Christian Grothoff + */ +#include "gfs_download.h" + + +struct Context +{ + + struct GNUNET_FUSE_PathInfo *path_info; + + struct GNUNET_FS_DownloadContext *dc; + + struct GNUNET_FS_Handle *fs; + + char *emsg; + + off_t start_offset; + + uint64_t length; + + int ret; + +}; + + +/** + * Task run when we shut down. + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Context *ctx = cls; + + if (NULL != ctx->dc) + { + GNUNET_FS_download_stop (ctx->dc, GNUNET_YES); + ctx->dc = NULL; + } + if (NULL != ctx->fs) + { + GNUNET_FS_stop (ctx->fs); + ctx->fs = NULL; + } +} + + +/** + * Function called from FS with progress information. + * + * @param cls our 'struct Context' + * @param info progress information + * @return NULL + */ +static void * +progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) +{ + struct Context *ctx = cls; + char *s; + + switch (info->status) + { + case GNUNET_FS_STATUS_DOWNLOAD_START: + GNUNET_break (info->value.download.dc == ctx->dc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Started download `%s'.\n", + info->value.download.filename); + break; + case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: + GNUNET_break (info->value.download.dc == ctx->dc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Downloading `%s' at %llu/%llu\n", + info->value.download.filename, + (unsigned long long) info->value.download.completed, + (unsigned long long) info->value.download.size); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ERROR: + GNUNET_break (info->value.download.dc == ctx->dc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Error downloading: %s.\n", + info->value.download.specifics.error.message); + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: + GNUNET_break (info->value.download.dc == ctx->dc); + s = + GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * + 1000 / + (info->value.download. + duration.rel_value + 1)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Downloading `%s' done (%s/s).\n", + info->value.download.filename, s); + GNUNET_free (s); + ctx->ret = 0; + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: + GNUNET_SCHEDULER_shutdown (); + break; + case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: + case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unexpected status: %d\n"), info->status); + break; + } + return NULL; +} + + +/** + * Main task run by the helper process which downloads the file. + * + * @param cls 'struct Context' with information about the download + * @param tc scheduler context + */ +static void +download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Context *ctx = cls; + + ctx->fs = GNUNET_FS_start (cfg, "gnunet-fuse", &progress_cb, ctx, + GNUNET_FS_FLAGS_NONE, + GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, 1, + GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, 1, + GNUNET_FS_OPTIONS_END); + if (NULL == ctx->fs) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not initialize `%s' subsystem.\n"), "FS"); + return; + } + ctx->dc = GNUNET_FS_download_start (ctx->fs, + ctx->path_info->uri, ctx->path_info->meta, + ctx->path_info->tmpfile, NULL, + (uint64_t) ctx->start_offset, + ctx->length, + anonymity_level, + GNUNET_FS_DOWNLOAD_OPTION_NONE, + NULL, NULL); + if (NULL == ctx->dc) + { + GNUNET_FS_stop (ctx->fs); + ctx->fs = NULL; + return; + } + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, ctx); +} + + +/** + * Download a file. Blocks until we're done. + * + * @param path_info information about the file to download + * @param start_offset offset of the first byte to download + * @param length number of bytes to download from 'start_offset' + * @return GNUNET_OK on success + */ +int +GNUNET_FUSE_download_file (struct GNUNET_FUSE_PathInfo *path_info, + off_t start_offset, + uint64_t length) +{ + struct Context ctx; + pid_t pid; + int status; + int ret; + + pid = fork (); + if (-1 == pid) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork"); + return GNUNET_SYSERR; + } + if (0 != pid) + { + while ( (0 != (ret = waitpid (pid, &status, 0))) && + (EINTR == errno) ) ; + if (0 != ret) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "waitpid"); + (void) kill (pid, SIGKILL); + (void) waitpid (pid, &status, 0); + return GNUNET_SYSERR; + } + if ( (WIFEXITED (status)) && + (0 == WEXITSTATUS (status)) ) + return GNUNET_OK; + return GNUNET_SYSERR; + } + memset (&ctx, 0, sizeof (ctx)); + ctx.ret = 1; + ctx.path_info = path_info; + ctx.start_offset = start_offset; + ctx.length = length; + GNUNET_SCHEDULER_run (&download_task, &ctx); + _exit (ret); +} + +/* end of fs_download.c */ diff --git a/src/fuse/gfs_download.h b/src/fuse/gfs_download.h @@ -0,0 +1,43 @@ +/* + This file is part of gnunet-fuse. + (C) 2012 Christian Grothoff (and other contributing authors) + + gnunet-fuse is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + 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 + +*/ +/** + * @file fuse/gfs_download.h + * @brief download files using FS + * @author Christian Grothoff + */ +#ifndef GFS_DOWNLOAD_H +#define GFS_DOWNLOAD_H + +#include "gnunet-fuse.h" + +/** + * Download a file. Blocks until we're done. + * + * @param path_info information about the file to download + * @param start_offset offset of the first byte to download + * @param length number of bytes to download from 'start_offset' + * @return GNUNET_OK on success + */ +int +GNUNET_FUSE_download_file (struct GNUNET_FUSE_PathInfo *path_info, + off_t start_offset, + uint64_t length); + +#endif diff --git a/src/fuse/gnunet-fuse.c b/src/fuse/gnunet-fuse.c @@ -26,6 +26,15 @@ */ #include "gnunet-fuse.h" +/** + * Anonymity level to use. + */ +unsigned int anonymity_level; + +/** + * Configuration to use. + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Return code from 'main' (0 on success). @@ -66,7 +75,7 @@ static struct GNUNET_Mutex *map_mutex; * @return NULL if no such path entry exists */ struct GNUNET_FUSE_PathInfo * -GNUNET_FUSE_get_path_info (const char *path) +GNUNET_FUSE_path_info_get (const char *path) { struct GNUNET_FUSE_PathInfo *pi; GNUNET_HashCode path_hash; @@ -210,12 +219,12 @@ cleanup_path_info (void *cls, const GNUNET_HashCode * key, void *value) * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration + * @param c configuration */ static void run (void *cls, char *const *args, - const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { static struct fuse_operations fops = { // .mkdir = gn_mkdir, @@ -239,6 +248,7 @@ run (void *cls, const char *path = "/"; struct GNUNET_FUSE_PathInfo *pi; + cfg = c; ret = 0; if (NULL == source) { diff --git a/src/fuse/gnunet-fuse.h b/src/fuse/gnunet-fuse.h @@ -37,6 +37,17 @@ /** + * Anonymity level to use. + */ +extern unsigned int anonymity_level; + +/** + * Configuration to use. + */ +extern const struct GNUNET_CONFIGURATION_Handle *cfg; + + +/** * struct containing mapped Path, with URI and other Information like Attributes etc. */ struct GNUNET_FUSE_PathInfo @@ -47,6 +58,11 @@ struct GNUNET_FUSE_PathInfo struct GNUNET_FS_Uri *uri; /** + * meta data to corresponding path (can be NULL) + */ + struct GNUNET_CONTAINER_MetaData *meta; + + /** * pathname */ char* path; diff --git a/src/fuse/readdir.c b/src/fuse/readdir.c @@ -46,205 +46,7 @@ * Introduced in version 2.3 */ #include "gnunet-fuse.h" - - -static int ret; - -static int verbose; - -static int delete_incomplete; - -static struct GNUNET_FS_DownloadContext *dc; - -static unsigned int parallelism = 16; - -static unsigned int request_parallelism = 4092; - -static int do_recursive; - -static int local_only; - -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -static unsigned int anonymity = 1; - -struct GNUNET_FS_Handle *fs; - -static struct GNUNET_FS_Handle *ctx; - -struct GNUNET_CONTAINER_MultiHashMap *map; - -struct GNUNET_FS_Uri *uri; - -char *emsg; - -struct GNUNET_FUSE_PathInfo *r; - - - - -static void -cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_FS_stop (ctx); - ctx = NULL; -} - -static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_FS_DownloadContext *d; - - if (dc != NULL) - { - d = dc; - dc = NULL; - GNUNET_FS_download_stop (d, delete_incomplete); - } -} - - -/* callback function */ -static void * -progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) -{ - - char *s; - char *s2; - char *t; - - switch (info->status) - { - case GNUNET_FS_STATUS_DOWNLOAD_START: - if (verbose > 1) - FPRINTF (stderr, _("Starting download `%s'.\n"), - info->value.download.filename); - break; - case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: - if (verbose) - { - s = - GNUNET_STRINGS_relative_time_to_string (info->value.download.eta); - if (info->value.download.specifics.progress. - block_download_duration.rel_value == - GNUNET_TIME_UNIT_FOREVER_REL.rel_value) - s2 = GNUNET_strdup (_("<unknown time>")); - else - s2 = - GNUNET_STRINGS_relative_time_to_string (info->value. - download.specifics. - progress.block_download_duration); - t = - GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * - 1000LL / - (info->value.download. - duration.rel_value + 1)); - FPRINTF (stdout, - _ - ("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), - info->value.download.filename, - (unsigned long long) info->value.download.completed, - (unsigned long long) info->value.download.size, s, t, s2); - GNUNET_free (s); - GNUNET_free (s2); - GNUNET_free (t); - } - break; - case GNUNET_FS_STATUS_DOWNLOAD_ERROR: - FPRINTF (stderr, _("Error downloading: %s.\n"), - info->value.download.specifics.error.message); - GNUNET_SCHEDULER_shutdown (); - break; - case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: - s = - GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * - 1000 / - (info->value.download. - duration.rel_value + 1)); - FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"), - info->value.download.filename, s); - GNUNET_free (s); - if (info->value.download.dc == dc) - GNUNET_SCHEDULER_shutdown (); - break; - case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: - if (info->value.download.dc == dc) - GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - break; - case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: - case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: - break; - default: - FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); - break; - } - - return NULL; -} - - -void -readdir_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - enum GNUNET_FS_DownloadOptions options; - - if (NULL == uri) - { - FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); - GNUNET_free (emsg); - GNUNET_FS_stop (ctx); // ?? hmmm....stop before start ?? - } - - - fs = GNUNET_FS_start (cfg, "gnunet-fuse", &progress_cb, NULL, - GNUNET_FS_FLAGS_NONE, - GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, parallelism, - GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, - request_parallelism, GNUNET_FS_OPTIONS_END); - - if (NULL == fs) - { - FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); - GNUNET_FS_uri_destroy (uri); - ret = 1; - return; - } - - options = GNUNET_FS_DOWNLOAD_OPTION_NONE; - if (do_recursive) - options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE; - if (local_only) - options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY; - - struct GNUNET_FS_DownloadContext *dc; - dc = GNUNET_FS_download_start (fs, uri, NULL, r->tmpfile, NULL, 0, - GNUNET_FS_uri_chk_get_file_size (uri), - anonymity, options, NULL, NULL); - - GNUNET_FS_uri_destroy (uri); - if (dc == NULL) - { - GNUNET_FS_stop (ctx); - ctx = NULL; - return; - } - - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, - NULL); - -} - - -static void -download_file (struct GNUNET_FUSE_PathInfo *path_info, - off_t start_offset, - uint64_t length) -{ - // FIXME: not implemented... - GNUNET_break (0); -} - +#include "gfs_download.h" /** * Closure for 'process_directory_entry'. @@ -317,7 +119,6 @@ int gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { - GNUNET_HashCode path_hash; struct GNUNET_FUSE_PathInfo *path_info; struct DepContext dc; size_t size; @@ -326,8 +127,7 @@ gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, struct GNUNET_DISK_MapHandle *mh; struct GNUNET_DISK_FileHandle *fh; - GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); - path_info = GNUNET_CONTAINER_multihashmap_get (map, &path_hash); + path_info = GNUNET_FUSE_path_info_get (path); if (NULL == path_info) { /* FIXME: we might need to check which of the ancestors @@ -340,11 +140,17 @@ gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, { /* store to temporary file */ path_info->tmpfile = GNUNET_DISK_mktemp ("gnunet-fuse-tempfile"); - download_file (path_info, - 0, - GNUNET_FS_uri_chk_get_file_size (path_info->uri)); - } - + if (GNUNET_OK != GNUNET_FUSE_download_file (path_info, + 0, + GNUNET_FS_uri_chk_get_file_size (path_info->uri))) + { + UNLINK (path_info->tmpfile); + GNUNET_free (path_info->tmpfile); + path_info->tmpfile = NULL; + GNUNET_FUSE_path_info_done (path_info); + return - EIO; /* low level IO error */ + } + } dc.filler = filler; dc.path = path; @@ -353,7 +159,10 @@ gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fh) + { + GNUNET_FUSE_path_info_done (path_info); return -EBADF; + } data = GNUNET_DISK_file_map (fh, &mh, GNUNET_DISK_MAP_TYPE_READ, @@ -361,6 +170,7 @@ gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, if (NULL == data) { GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); + GNUNET_FUSE_path_info_done (path_info); return -EBADF; } if (GNUNET_OK != @@ -377,5 +187,6 @@ gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_unmap (mh)); GNUNET_DISK_file_close (fh); + GNUNET_FUSE_path_info_done (path_info); return ret; }