gnunet-fuse

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

read.c (4787B)


      1 /*
      2   This file is part of gnunet-fuse.
      3   Copyright (C) 2012 GNUnet e.V.
      4   
      5   gnunet-fuse is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as published
      7   by the Free Software Foundation; either version 3, or (at your
      8   option) any later version.
      9  
     10   gnunet-fuse is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14  
     15   You should have received a copy of the GNU General Public License
     16   along with this program; if not, write to the Free Software
     17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
     18 
     19 */
     20 /*
     21  * read.c - FUSE read function
     22  *
     23  *  Created on: Mar 14, 2012
     24  *      Author: mg
     25  *
     26  *		 Read data from an open file
     27  *
     28  * Read should return exactly the number of bytes requested except
     29  * on EOF or error, otherwise the rest of the data will be
     30  * substituted with zeroes.	 An exception to this is when the
     31  * 'direct_io' mount option is specified, in which case the return
     32  * value of the read system call will reflect the return value of
     33  * this operation.
     34  *
     35  * Changed in version 2.2
     36  */
     37 
     38 /**
     39  * @file fuse/read.c
     40  * @brief reading files
     41  * @author Christian Grothoff
     42  */
     43 #include "gnunet-fuse.h"
     44 #include "gfs_download.h"
     45 
     46 
     47 
     48 int
     49 gn_read (const char *path, char *buf, size_t size, off_t offset,
     50 	 struct fuse_file_info *fi)
     51 {
     52   struct GNUNET_FUSE_PathInfo *path_info;
     53   uint64_t fsize;
     54   struct GNUNET_DISK_FileHandle *fh;
     55   int eno;
     56 
     57   path_info = GNUNET_FUSE_path_info_get (path, &eno);
     58   if (NULL == path_info)
     59     return - eno;
     60   fsize = GNUNET_FS_uri_chk_get_file_size (path_info->uri);
     61   if (offset > fsize)
     62   {
     63     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
     64 		"No data available at offset %llu of file `%s'\n",
     65 		(unsigned long long) offset,
     66 		path);
     67     return 0; 
     68   }
     69   if (offset + size > fsize)
     70     size = fsize - offset;
     71   if (NULL == path_info->tmpfile)
     72   {
     73     /* store to temporary file */
     74     path_info->tmpfile = GNUNET_DISK_mktemp ("gnunet-fuse-tempfile");
     75     if (GNUNET_OK != GNUNET_FUSE_download_file (path_info, 
     76 						offset,
     77 						size))
     78     {
     79       unlink (path_info->tmpfile);
     80       GNUNET_free (path_info->tmpfile);
     81       path_info->tmpfile = NULL;
     82       GNUNET_FUSE_path_info_done (path_info);
     83       return - EIO; /* low level IO error */
     84     }
     85   } 
     86   else
     87   {
     88     if ( (offset < path_info->download_start) ||
     89 	 (size + offset > path_info->download_end) )
     90     {
     91       /* need to download some more... */
     92       if (GNUNET_OK != GNUNET_FUSE_download_file (path_info, 
     93 						  offset,
     94 						  size))
     95       {
     96 	unlink (path_info->tmpfile);
     97 	GNUNET_free (path_info->tmpfile);
     98 	path_info->tmpfile = NULL;
     99 	GNUNET_FUSE_path_info_done (path_info);
    100 	return - EIO; /* low level IO error */
    101       }
    102     }
    103   }
    104   /* combine ranges */
    105   if (path_info->download_start == path_info->download_end)
    106   {
    107     /* first range */
    108     path_info->download_start = offset;
    109     path_info->download_end = offset + size;
    110   }
    111   else
    112   {
    113     /* only combine ranges if the resulting range would
    114        be contiguous... */
    115     if ( (offset >= path_info->download_start) &&
    116 	 (offset <= path_info->download_end) &&
    117 	 (offset + size > path_info->download_end) )
    118       path_info->download_end = offset + size;
    119     if ( (offset + size >= path_info->download_start) &&
    120 	 (offset + size <= path_info->download_end) &&
    121 	 (offset < path_info->download_start) )
    122       path_info->download_start = offset;
    123   }
    124 
    125 
    126   fh = GNUNET_DISK_file_open (path_info->tmpfile,
    127 			      GNUNET_DISK_OPEN_READ,
    128 			      GNUNET_DISK_PERM_NONE);			      
    129   if (NULL == fh)
    130   {
    131     GNUNET_FUSE_path_info_done (path_info);
    132     return - EBADF;
    133   }
    134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
    135 	      "Trying to read bytes %llu-%llu/%llu of file `%s'\n",
    136 	      (unsigned long long) offset,
    137 	      (unsigned long long) offset + size,
    138 	      (unsigned long long) fsize,
    139 	      path);	      
    140   if (offset != GNUNET_DISK_file_seek (fh, offset, GNUNET_DISK_SEEK_SET))
    141   {
    142     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
    143 		"No data available at offset %llu of file `%s'\n",
    144 		(unsigned long long) offset,
    145 		path);
    146     GNUNET_DISK_file_close (fh);
    147     GNUNET_FUSE_path_info_done (path_info);
    148     return 0; 
    149   }
    150   size = GNUNET_MIN (size, fsize - offset);
    151   if (GNUNET_SYSERR == (size = GNUNET_DISK_file_read (fh, buf, size)))
    152   {
    153     int eno = errno;
    154     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
    155 		"Error reading from file `%s': %s\n",
    156 		path,
    157 		strerror (errno));
    158     GNUNET_DISK_file_close (fh);
    159     GNUNET_FUSE_path_info_done (path_info);
    160     return - eno; 
    161   }
    162   GNUNET_DISK_file_close (fh);
    163   GNUNET_FUSE_path_info_done (path_info);
    164   return size;
    165 }
    166 
    167 /* end of read.c */
    168