From 71eacc6a3ee0003df1485d15c44e9b7306105d48 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 6 Jun 2012 11:44:47 +0000 Subject: finishing read-only implementation of fuse for 0.9.3 --- src/fuse/getattr.c | 5 +- src/fuse/gnunet-fuse.c | 302 ++++++++++++++++++++++++++++++++++++++----------- src/fuse/gnunet-fuse.h | 95 +++++++++++++--- src/fuse/open.c | 7 +- src/fuse/read.c | 59 ++++++++-- src/fuse/readdir.c | 148 ++---------------------- 6 files changed, 385 insertions(+), 231 deletions(-) diff --git a/src/fuse/getattr.c b/src/fuse/getattr.c index 9bf1c9c..abf5faa 100644 --- a/src/fuse/getattr.c +++ b/src/fuse/getattr.c @@ -43,10 +43,11 @@ int gn_getattr (const char *path, struct stat *stbuf) { struct GNUNET_FUSE_PathInfo *pi; + int eno; - pi = GNUNET_FUSE_path_info_get (path); + pi = GNUNET_FUSE_path_info_get (path, &eno); if (NULL == pi) - return - ENOENT; + return - eno; *stbuf = pi->stbuf; GNUNET_FUSE_path_info_done (pi); return 0; diff --git a/src/fuse/gnunet-fuse.c b/src/fuse/gnunet-fuse.c index a0b43de..69c226c 100644 --- a/src/fuse/gnunet-fuse.c +++ b/src/fuse/gnunet-fuse.c @@ -25,6 +25,7 @@ * @author Mauricio Günther */ #include "gnunet-fuse.h" +#include "gfs_download.h" /** * Anonymity level to use. @@ -57,35 +58,181 @@ static char *source; static char *directory; /** - * Global mapping of paths to GNUnet URIs (and file names) for - * the respective entries. + * Root of the file tree. */ -static struct GNUNET_CONTAINER_MultiHashMap *map; +static struct GNUNET_FUSE_PathInfo *root; + /** - * Mutex for synchronizing access to 'map'. + * Function used to process entries in a directory; adds the + * respective entry to the parent directory. + * + * @param cls closure with the 'struct GNUNET_FUSE_PathInfo' of the parent + * @param filename name of the file in the directory + * @param uri URI of the file + * @param metadata metadata for the file; metadata for + * the directory if everything else is NULL/zero + * @param length length of the available data for the file + * (of type size_t since data must certainly fit + * into memory; if files are larger than size_t + * permits, then they will certainly not be + * embedded with the directory itself). + * @param data data available for the file (length bytes) */ -static struct GNUNET_Mutex *map_mutex; +static void +process_directory_entry (void *cls, + const char *filename, + const struct GNUNET_FS_Uri * + uri, + const struct + GNUNET_CONTAINER_MetaData * + meta, size_t length, + const void *data) +{ + struct GNUNET_FUSE_PathInfo *parent = cls; + struct GNUNET_FUSE_PathInfo *pi; + int is_directory; + + if (NULL == filename) + return; /* info about the directory itself */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding file `%s' to directory `%s'\n", + filename, + parent->filename); + is_directory = GNUNET_FS_meta_data_test_for_directory (meta); + if (GNUNET_SYSERR == is_directory) + is_directory = GNUNET_NO; /* if in doubt, say no */ + pi = GNUNET_FUSE_path_info_create (parent, filename, uri, is_directory); + GNUNET_FUSE_path_info_done (pi); +} + + +/** + * Load and parse a directory. + * + * @param pi path to the directory + * @param eno where to store 'errno' on errors + * @return GNUNET_OK on success + */ +int +GNUNET_FUSE_load_directory (struct GNUNET_FUSE_PathInfo *pi, + int * eno) +{ + size_t size; + void *data; + struct GNUNET_DISK_MapHandle *mh; + struct GNUNET_DISK_FileHandle *fh; + + /* Need to download directory; store to temporary file */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Downloading directory `%s'\n", + pi->filename); + pi->tmpfile = GNUNET_DISK_mktemp ("gnunet-fuse-tempfile"); + if (GNUNET_OK != GNUNET_FUSE_download_file (pi, + 0, + GNUNET_FS_uri_chk_get_file_size (pi->uri))) + { + UNLINK (pi->tmpfile); + GNUNET_free (pi->tmpfile); + pi->tmpfile = NULL; + *eno = EIO; /* low level IO error */ + return GNUNET_SYSERR; + } + + size = (size_t) GNUNET_FS_uri_chk_get_file_size (pi->uri); + fh = GNUNET_DISK_file_open (pi->tmpfile, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fh) + { + *eno = EIO; + return GNUNET_SYSERR; + } + data = GNUNET_DISK_file_map (fh, + &mh, + GNUNET_DISK_MAP_TYPE_READ, + size); + if (NULL == data) + { + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); + return - ENOMEM; + } + *eno = 0; + if (GNUNET_OK != + GNUNET_FS_directory_list_contents (size, + data, 0LL, + &process_directory_entry, + pi)) + *eno = ENOTDIR; + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_unmap (mh)); + GNUNET_DISK_file_close (fh); + if (0 != *eno) + return GNUNET_SYSERR; + return GNUNET_OK; +} /** * Obtain an existing path info entry from the global map. * * @param path path the entry represents + * @param eno where to store 'errno' on errors * @return NULL if no such path entry exists */ struct GNUNET_FUSE_PathInfo * -GNUNET_FUSE_path_info_get (const char *path) +GNUNET_FUSE_path_info_get (const char *path, + int *eno) { + size_t slen = strlen (path) + 1; + char buf[slen]; struct GNUNET_FUSE_PathInfo *pi; - GNUNET_HashCode path_hash; - - GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); - GNUNET_mutex_lock (map_mutex); - pi = GNUNET_CONTAINER_multihashmap_get (map, &path_hash); - if (NULL != pi) - ++pi->rc; - GNUNET_mutex_unlock (map_mutex); + struct GNUNET_FUSE_PathInfo *pos; + char *tok; + + memcpy (buf, path, slen); + pi = root; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up path `%s'\n", + path); + GNUNET_mutex_lock (pi->lock); + for (tok = strtok (buf, "/"); NULL != tok; tok = strtok (NULL, "/")) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Searching for token `%s'\n", + tok); + if (NULL == pi->tmpfile) + { + if (GNUNET_OK != GNUNET_FUSE_load_directory (pi, eno)) + { + GNUNET_mutex_unlock (pi->lock); + return NULL; + } + } + + pos = pi->child_head; + while ( (NULL != pos) && + (0 != strcmp (tok, + pos->filename)) ) + pos = pos->next; + if (NULL == pos) + { + GNUNET_mutex_unlock (pi->lock); + *eno = ENOENT; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No file with name `%s' in directory `%s'\n", + tok, + pi->filename); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Descending into directory `%s'\n", + tok); + GNUNET_mutex_lock (pos->lock); + GNUNET_mutex_unlock (pi->lock); + pi = pos; + } + ++pi->rc; + GNUNET_mutex_unlock (pi->lock); return pi; } @@ -93,36 +240,37 @@ GNUNET_FUSE_path_info_get (const char *path) /** * Create a new path info entry in the global map. * - * @param path path the entry represents + * @param parent parent directory (can be NULL) + * @param filename name of the file to create * @param uri URI to use for the path + * @param is_directory GNUNET_YES if this entry is for a directory * @return existing path entry if one already exists, otherwise - * new path entry with the desired URI + * new path entry with the desired URI; in both cases + * the reference counter has been incremented by 1 */ struct GNUNET_FUSE_PathInfo * -GNUNET_FUSE_path_info_create (const char *path, +GNUNET_FUSE_path_info_create (struct GNUNET_FUSE_PathInfo *parent, + const char *filename, const struct GNUNET_FS_Uri *uri, int is_directory) { struct GNUNET_FUSE_PathInfo *pi; - GNUNET_HashCode path_hash; + size_t len; - GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); - GNUNET_mutex_lock (map_mutex); - pi = GNUNET_CONTAINER_multihashmap_get (map, &path_hash); - if (NULL != pi) + if (NULL != parent) { - GNUNET_mutex_unlock (map_mutex); - return pi; + GNUNET_mutex_lock (parent->lock); } + pi = GNUNET_malloc (sizeof (struct GNUNET_FUSE_PathInfo)); - pi->path = GNUNET_strdup (path); + pi->parent = parent; + pi->filename = GNUNET_strdup (filename); + len = strlen (pi->filename); + if ('/' == pi->filename[len - 1]) + pi->filename[len - 1] = '\0'; pi->uri = GNUNET_FS_uri_dup (uri); pi->lock = GNUNET_mutex_create (GNUNET_YES); pi->rc = 1; - GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (map, - &path_hash, - pi, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); pi->stbuf.st_mode = (S_IRUSR | S_IRGRP | S_IROTH); /* read-only */ if (GNUNET_YES == is_directory) { @@ -133,7 +281,14 @@ GNUNET_FUSE_path_info_create (const char *path, pi->stbuf.st_mode |= S_IFREG; /* regular file */ pi->stbuf.st_size = (off_t) GNUNET_FS_uri_chk_get_file_size (uri); } - GNUNET_mutex_unlock (map_mutex); + + if (NULL != parent) + { + GNUNET_CONTAINER_DLL_insert_tail (parent->child_head, + parent->child_tail, + pi); + GNUNET_mutex_unlock (parent->lock); + } return pi; } @@ -151,14 +306,14 @@ GNUNET_FUSE_path_info_done (struct GNUNET_FUSE_PathInfo *pi) (void) GNUNET_FUSE_path_info_delete (pi); return; } - GNUNET_mutex_lock (map_mutex); + GNUNET_mutex_lock (pi->lock); --pi->rc; - GNUNET_mutex_unlock (map_mutex); + GNUNET_mutex_unlock (pi->lock); } /** - * Delete a path info entry from the global map (does not actually + * Delete a path info entry from the tree (does not actually * remove anything from the file system). Also decrements the RC. * * @param pi entry to remove @@ -166,19 +321,32 @@ GNUNET_FUSE_path_info_done (struct GNUNET_FUSE_PathInfo *pi) */ int GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi) -{ - GNUNET_HashCode path_hash; - int ret; +{ + struct GNUNET_FUSE_PathInfo *parent = pi->parent; int rc; + int ret; - GNUNET_CRYPTO_hash (pi->path, strlen (pi->path), &path_hash); - GNUNET_mutex_lock (map_mutex); - ret = GNUNET_CONTAINER_multihashmap_remove (map, &path_hash, pi); + if (NULL != parent) + { + ret = 0; + GNUNET_mutex_lock (parent->lock); + GNUNET_mutex_lock (pi->lock); + GNUNET_CONTAINER_DLL_remove (parent->child_head, + parent->child_tail, + pi); + pi->parent = NULL; + GNUNET_mutex_unlock (parent->lock); + } + else + { + ret = - ENOENT; + GNUNET_mutex_lock (pi->lock); + } rc = --pi->rc; - GNUNET_mutex_unlock (map_mutex); if (0 != rc) { pi->delete_later = GNUNET_YES; + GNUNET_mutex_unlock (pi->lock); } else { @@ -187,33 +355,30 @@ GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi) GNUNET_break (0 == UNLINK (pi->tmpfile)); GNUNET_free (pi->tmpfile); } - GNUNET_free (pi->path); + GNUNET_free (pi->filename); GNUNET_FS_uri_destroy (pi->uri); + GNUNET_mutex_unlock (pi->lock); GNUNET_mutex_destroy (pi->lock); GNUNET_free (pi); } - if (GNUNET_YES == ret) - return 0; - return - ENOENT; + return ret; } /** - * Called on each entry in our global 'map' to clean it up. + * Called on each node in the path info tree to clean it up. * - * @param cls closure, NULL - * @param key current key code - * @param value value in the hash map, a 'struct GNUNET_FUSE_PathInfo' - * @return GNUNET_YES (we should continue to iterate) + * @param pi path info to clean up */ -static int -cleanup_path_info (void *cls, const GNUNET_HashCode * key, void *value) +static void +cleanup_path_info (struct GNUNET_FUSE_PathInfo *pi) { - struct GNUNET_FUSE_PathInfo *pi = value; + struct GNUNET_FUSE_PathInfo *pos; + while (NULL != (pos = pi->child_head)) + cleanup_path_info (pos); ++pi->rc; (void) GNUNET_FUSE_path_info_delete (pi); - return GNUNET_YES; } @@ -249,8 +414,7 @@ run (void *cls, int argc; struct GNUNET_FS_Uri *uri; char *emsg; - const char *path = "/"; - struct GNUNET_FUSE_PathInfo *pi; + int eno; cfg = c; ret = 0; @@ -279,20 +443,31 @@ run (void *cls, (GNUNET_YES != GNUNET_FS_uri_test_loc (uri)) ) { fprintf (stderr, - _("The given URI is not for a directory and can thus not be mounted\n"), - emsg); + _("The given URI is not for a directory and can thus not be mounted\n")); ret = 4; + GNUNET_FS_uri_destroy (uri); return; } - map_mutex = GNUNET_mutex_create (GNUNET_NO); - map = GNUNET_CONTAINER_multihashmap_create (1024); - pi = GNUNET_FUSE_path_info_create (path, uri, GNUNET_YES); + root = GNUNET_FUSE_path_info_create (NULL, "/", uri, GNUNET_YES); + if (GNUNET_OK != + GNUNET_FUSE_load_directory (root, &eno)) + { + fprintf (stderr, + _("Failed to mount `%s': %s\n"), + source, + STRERROR (eno)); + ret = 5; + cleanup_path_info (root); + GNUNET_FS_uri_destroy (uri); + return; + } if (GNUNET_YES == single_threaded) argc = 5; else argc = 2; + { char *a[argc + 1]; a[0] = "gnunet-fuse"; @@ -306,12 +481,7 @@ run (void *cls, a[argc] = NULL; fuse_main (argc, a, &fops, NULL); } - GNUNET_FUSE_path_info_done (pi); - GNUNET_CONTAINER_multihashmap_iterate (map, &cleanup_path_info, NULL); - GNUNET_CONTAINER_multihashmap_destroy (map); - map = NULL; - GNUNET_mutex_destroy (map_mutex); - map_mutex = NULL; + cleanup_path_info (root); GNUNET_FS_uri_destroy (uri); } diff --git a/src/fuse/gnunet-fuse.h b/src/fuse/gnunet-fuse.h index d8f567b..99137d8 100644 --- a/src/fuse/gnunet-fuse.h +++ b/src/fuse/gnunet-fuse.h @@ -52,8 +52,36 @@ extern const struct GNUNET_CONFIGURATION_Handle *cfg; */ struct GNUNET_FUSE_PathInfo { + + /** + * All files in a directory are kept in a DLL. + */ + struct GNUNET_FUSE_PathInfo *next; + + /** + * All files in a directory are kept in a DLL. + */ + struct GNUNET_FUSE_PathInfo *prev; + + /** + * Parent directory, NULL for the root. + */ + struct GNUNET_FUSE_PathInfo *parent; + /** - * uri to corresponding path + * Head of linked list of entries in this directory + * (NULL if this is a file). + */ + struct GNUNET_FUSE_PathInfo *child_head; + + /** + * Head of linked list of entries in this directory + * (NULL if this is a file). + */ + struct GNUNET_FUSE_PathInfo *child_tail; + + /** + * URI of the file or directory. */ struct GNUNET_FS_Uri *uri; @@ -63,14 +91,15 @@ struct GNUNET_FUSE_PathInfo struct GNUNET_CONTAINER_MetaData *meta; /** - * pathname + * Name of the file for this path (i.e. "home"). '/' for the root (all other + * filenames must not contain '/') */ - char* path; + char *filename; /** - * name of temporary file + * Name of temporary file, NULL if we never accessed this file or directory. */ - char* tmpfile; + char *tmpfile; /** * file attributes @@ -78,12 +107,25 @@ struct GNUNET_FUSE_PathInfo struct stat stbuf; /** - * Lock for exclusive access to this struct. + * Lock for exclusive access to this struct (i.e. for downloading blocks). + * Lock order: always lock parents before children. */ struct GNUNET_Mutex *lock; /** - * Reference counter. + * Beginning of a contiguous range of blocks of the file what we + * have downloaded already to 'tmpfile'. + */ + uint64_t download_start; + + /** + * End of a contiguous range of blocks of the file what we + * have downloaded already to 'tmpfile'. + */ + uint64_t download_end; + + /** + * Reference counter (used if the file is deleted while being opened, etc.) */ unsigned int rc; @@ -97,7 +139,8 @@ struct GNUNET_FUSE_PathInfo /** * Create a new path info entry in the global map. * - * @param path path the entry represents + * @param parent parent directory (can be NULL) + * @param filename name of the file to create * @param uri URI to use for the path * @param is_directory GNUNET_YES if this entry is for a directory * @return existing path entry if one already exists, otherwise @@ -105,7 +148,8 @@ struct GNUNET_FUSE_PathInfo * the reference counter has been incremented by 1 */ struct GNUNET_FUSE_PathInfo * -GNUNET_FUSE_path_info_create (const char *path, +GNUNET_FUSE_path_info_create (struct GNUNET_FUSE_PathInfo *parent, + const char *filename, const struct GNUNET_FS_Uri *uri, int is_directory); @@ -114,11 +158,13 @@ GNUNET_FUSE_path_info_create (const char *path, * Obtain an existing path info entry from the global map. * * @param path path the entry represents + * @param eno where to store 'errno' on errors * @return NULL if no such path entry exists, otherwise * an entry with incremented reference counter (!) */ struct GNUNET_FUSE_PathInfo * -GNUNET_FUSE_path_info_get (const char *path); +GNUNET_FUSE_path_info_get (const char *path, + int *eno); /** @@ -141,9 +187,30 @@ int GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi); +/** + * Load and parse a directory. + * + * @param pi path to the directory + * @param eno where to store 'errno' on errors + * @return GNUNET_OK on success + */ +int +GNUNET_FUSE_load_directory (struct GNUNET_FUSE_PathInfo *pi, + int * eno); + + /* FUSE function files */ int gn_getattr(const char *path, struct stat *stbuf); +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_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi); + + int gn_mknod(const char *path, mode_t mode, dev_t rdev); int gn_mkdir(const char *path, mode_t mode); @@ -156,19 +223,11 @@ int gn_rename(const char *from, const char *to); int gn_truncate(const char *path, off_t size); -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, 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); -int gn_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi); - int gn_utimens(const char *path, const struct timespec ts[2]); diff --git a/src/fuse/open.c b/src/fuse/open.c index 3f31661..fe14c2e 100644 --- a/src/fuse/open.c +++ b/src/fuse/open.c @@ -54,10 +54,13 @@ int gn_open (const char *path, struct fuse_file_info *fi) { struct GNUNET_FUSE_PathInfo *pi; + int eno; - pi = GNUNET_FUSE_path_info_get (path); + pi = GNUNET_FUSE_path_info_get (path, &eno); if (NULL == pi) - return - ENOENT; + return - eno; + /* NOTE: once we allow writes, we need to keep the RC + incremented until close... */ GNUNET_FUSE_path_info_done (pi); if (O_RDONLY != (fi->flags & 3)) return - EACCES; diff --git a/src/fuse/read.c b/src/fuse/read.c index d6774e0..de950a8 100644 --- a/src/fuse/read.c +++ b/src/fuse/read.c @@ -52,15 +52,22 @@ gn_read (const char *path, char *buf, size_t size, off_t offset, struct GNUNET_FUSE_PathInfo *path_info; uint64_t fsize; struct GNUNET_DISK_FileHandle *fh; + int eno; - path_info = GNUNET_FUSE_path_info_get (path); + path_info = GNUNET_FUSE_path_info_get (path, &eno); if (NULL == path_info) + return - eno; + fsize = GNUNET_FS_uri_chk_get_file_size (path_info->uri); + if (offset > fsize) { - /* FIXME: we might need to check which of the ancestors - exist and possibly download ancestral directories, - instead of directly giving up here... */ - return - ENOENT; - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No data available at offset %llu of file `%s'\n", + (unsigned long long) offset, + path); + return 0; + } + if (offset + size > fsize) + size = fsize - offset; if (NULL == path_info->tmpfile) { /* store to temporary file */ @@ -76,8 +83,46 @@ gn_read (const char *path, char *buf, size_t size, off_t offset, return - EIO; /* low level IO error */ } } + else + { + if ( (offset < path_info->download_start) || + (size + offset > path_info->download_end) ) + { + /* need to download some more... */ + if (GNUNET_OK != GNUNET_FUSE_download_file (path_info, + offset, + size)) + { + 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 */ + } + } + } + /* combine ranges */ + if (path_info->download_start == path_info->download_end) + { + /* first range */ + path_info->download_start = offset; + path_info->download_end = offset + size; + } + else + { + /* only combine ranges if the resulting range would + be contiguous... */ + if ( (offset >= path_info->download_start) && + (offset <= path_info->download_end) && + (offset + size > path_info->download_end) ) + path_info->download_end = offset + size; + if ( (offset + size >= path_info->download_start) && + (offset + size <= path_info->download_end) && + (offset < path_info->download_start) ) + path_info->download_start = offset; + } + - fsize = GNUNET_FS_uri_chk_get_file_size (path_info->uri); fh = GNUNET_DISK_file_open (path_info->tmpfile, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); diff --git a/src/fuse/readdir.c b/src/fuse/readdir.c index 9cb914b..32bd10d 100644 --- a/src/fuse/readdir.c +++ b/src/fuse/readdir.c @@ -53,153 +53,29 @@ #include "gnunet-fuse.h" #include "gfs_download.h" -/** - * Closure for 'process_directory_entry'. - */ -struct DepContext -{ - /** - * Function to call on each entry. - */ - fuse_fill_dir_t filler; - - /** - * 'buf' argument to give to filler. - */ - void *buf; - - /** - * Basepath to add for the entries. - */ - const char *path; -}; - - -/** - * Function used to process entries in a directory. - * - * @param cls closure - * @param filename name of the file in the directory - * @param uri URI of the file - * @param metadata metadata for the file; metadata for - * the directory if everything else is NULL/zero - * @param length length of the available data for the file - * (of type size_t since data must certainly fit - * into memory; if files are larger than size_t - * permits, then they will certainly not be - * embedded with the directory itself). - * @param data data available for the file (length bytes) - */ -static void -process_directory_entry (void *cls, - const char *filename, - const struct GNUNET_FS_Uri * - uri, - const struct - GNUNET_CONTAINER_MetaData * - meta, size_t length, - const void *data) -{ - struct DepContext *dc = cls; - struct GNUNET_FUSE_PathInfo *pi; - char *path; - int is_directory; - - if (NULL == filename) - return; /* info about the directory itself */ - GNUNET_asprintf (&path, - "%s%s", - dc->path, - filename); - is_directory = GNUNET_FS_meta_data_test_for_directory (meta); - if (GNUNET_SYSERR == is_directory) - is_directory = GNUNET_NO; /* if in doubt, say no */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Listing filename `%s' in directory `%s' (%s)\n", - filename, - dc->path, - path); - pi = GNUNET_FUSE_path_info_create (path, uri, is_directory); - dc->filler (dc->buf, - filename, - &pi->stbuf, - 0); - GNUNET_FUSE_path_info_done (pi); -} - int gn_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct GNUNET_FUSE_PathInfo *path_info; - struct DepContext dc; - size_t size; - int ret; - void *data; - struct GNUNET_DISK_MapHandle *mh; - struct GNUNET_DISK_FileHandle *fh; + struct GNUNET_FUSE_PathInfo *pos; + int eno; - path_info = GNUNET_FUSE_path_info_get (path); + path_info = GNUNET_FUSE_path_info_get (path, &eno); if (NULL == path_info) - { - /* FIXME: we might need to check which of the ancestors - exist and possibly download ancestral directories, - instead of directly giving up here... */ - return - ENOENT; - } - - if (NULL == path_info->tmpfile) - { - /* store to temporary file */ - path_info->tmpfile = GNUNET_DISK_mktemp ("gnunet-fuse-tempfile"); - 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; - dc.buf = buf; - size = (size_t) GNUNET_FS_uri_chk_get_file_size (path_info->uri); - fh = GNUNET_DISK_file_open (path_info->tmpfile, - 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, - size); - if (NULL == data) - { - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); - GNUNET_FUSE_path_info_done (path_info); - return -EBADF; - } + return - eno; + if ( (NULL == path_info->tmpfile) && + (GNUNET_OK != GNUNET_FUSE_load_directory (path_info, &eno)) ) + return - eno; filler (buf, ".", NULL, 0); filler (buf, "..", NULL, 0); - ret = 0; - if (GNUNET_OK != - GNUNET_FS_directory_list_contents (size, - data, 0LL, - &process_directory_entry, - &dc)) - ret = - EIO; - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_unmap (mh)); - GNUNET_DISK_file_close (fh); + for (pos = path_info->child_head; NULL != pos; pos = pos->next) + filler (buf, pos->filename, + &pos->stbuf, + 0); GNUNET_FUSE_path_info_done (path_info); - return ret; + return 0; } /* end of readdir.c */ -- cgit v1.2.3