gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r21775 - gnunet-fuse/src/fuse


From: gnunet
Subject: [GNUnet-SVN] r21775 - gnunet-fuse/src/fuse
Date: Wed, 6 Jun 2012 13:44:47 +0200

Author: grothoff
Date: 2012-06-06 13:44:47 +0200 (Wed, 06 Jun 2012)
New Revision: 21775

Modified:
   gnunet-fuse/src/fuse/getattr.c
   gnunet-fuse/src/fuse/gnunet-fuse.c
   gnunet-fuse/src/fuse/gnunet-fuse.h
   gnunet-fuse/src/fuse/open.c
   gnunet-fuse/src/fuse/read.c
   gnunet-fuse/src/fuse/readdir.c
Log:
finishing read-only implementation of fuse for 0.9.3

Modified: gnunet-fuse/src/fuse/getattr.c
===================================================================
--- gnunet-fuse/src/fuse/getattr.c      2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/getattr.c      2012-06-06 11:44:47 UTC (rev 21775)
@@ -43,10 +43,11 @@
 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;

Modified: gnunet-fuse/src/fuse/gnunet-fuse.c
===================================================================
--- gnunet-fuse/src/fuse/gnunet-fuse.c  2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/gnunet-fuse.c  2012-06-06 11:44:47 UTC (rev 21775)
@@ -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 *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;
+  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; 
+      }
+    }
 
-  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);
+    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 @@
 /**
  * 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 @@
     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 @@
     (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 @@
  */
 int
 GNUNET_FUSE_path_info_delete (struct GNUNET_FUSE_PathInfo *pi)
-{
-  GNUNET_HashCode path_hash;
+{  
+  struct GNUNET_FUSE_PathInfo *parent = pi->parent;
+  int rc;
   int ret;
-  int rc;
 
-  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_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 @@
   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 @@
        (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 @@
     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);
 }
 

Modified: gnunet-fuse/src/fuse/gnunet-fuse.h
===================================================================
--- gnunet-fuse/src/fuse/gnunet-fuse.h  2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/gnunet-fuse.h  2012-06-06 11:44:47 UTC (rev 21775)
@@ -52,9 +52,37 @@
  */
 struct GNUNET_FUSE_PathInfo
 {
+
   /**
-   * uri to corresponding path 
+   * 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;
+
+  /**
+   * 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_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,13 +107,26 @@
   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 @@
 /**
  * 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 @@
  *         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 @@
  * 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 @@
 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_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]);
 
 

Modified: gnunet-fuse/src/fuse/open.c
===================================================================
--- gnunet-fuse/src/fuse/open.c 2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/open.c 2012-06-06 11:44:47 UTC (rev 21775)
@@ -54,10 +54,13 @@
 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;

Modified: gnunet-fuse/src/fuse/read.c
===================================================================
--- gnunet-fuse/src/fuse/read.c 2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/read.c 2012-06-06 11:44:47 UTC (rev 21775)
@@ -52,15 +52,22 @@
   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 @@
       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);                         

Modified: gnunet-fuse/src/fuse/readdir.c
===================================================================
--- gnunet-fuse/src/fuse/readdir.c      2012-06-06 10:54:07 UTC (rev 21774)
+++ gnunet-fuse/src/fuse/readdir.c      2012-06-06 11:44:47 UTC (rev 21775)
@@ -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 */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]