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