1 /* GIO - GLib Input, Output and Streaming Library 2 * 3 * Copyright (C) 2006-2007 Red Hat, Inc. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library 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 GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General 16 * Public License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 18 * Boston, MA 02111-1307, USA. 19 * 20 * Author: Alexander Larsson <alexl (at) redhat.com> 21 */ 22 23 #include "config.h" 24 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <fcntl.h> 28 #ifdef HAVE_UNISTD_H 29 #include <unistd.h> 30 #endif 31 #include <errno.h> 32 33 #include <glib.h> 34 #include <glib/gstdio.h> 35 #include "gcancellable.h" 36 #include "gioerror.h" 37 #include "glocalfileinputstream.h" 38 #include "glocalfileinfo.h" 39 #include "glibintl.h" 40 41 #ifdef G_OS_WIN32 42 #include <io.h> 43 #endif 44 45 #include "gioalias.h" 46 47 #define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type 48 G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM); 49 50 struct _GLocalFileInputStreamPrivate { 51 int fd; 52 }; 53 54 static gssize g_local_file_input_stream_read (GInputStream *stream, 55 void *buffer, 56 gsize count, 57 GCancellable *cancellable, 58 GError **error); 59 static gssize g_local_file_input_stream_skip (GInputStream *stream, 60 gsize count, 61 GCancellable *cancellable, 62 GError **error); 63 static gboolean g_local_file_input_stream_close (GInputStream *stream, 64 GCancellable *cancellable, 65 GError **error); 66 static goffset g_local_file_input_stream_tell (GFileInputStream *stream); 67 static gboolean g_local_file_input_stream_can_seek (GFileInputStream *stream); 68 static gboolean g_local_file_input_stream_seek (GFileInputStream *stream, 69 goffset offset, 70 GSeekType type, 71 GCancellable *cancellable, 72 GError **error); 73 static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream *stream, 74 const char *attributes, 75 GCancellable *cancellable, 76 GError **error); 77 78 static void 79 g_local_file_input_stream_finalize (GObject *object) 80 { 81 GLocalFileInputStream *file; 82 83 file = G_LOCAL_FILE_INPUT_STREAM (object); 84 85 G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize (object); 86 } 87 88 static void 89 g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass) 90 { 91 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 92 GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); 93 GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass); 94 95 g_type_class_add_private (klass, sizeof (GLocalFileInputStreamPrivate)); 96 97 gobject_class->finalize = g_local_file_input_stream_finalize; 98 99 stream_class->read_fn = g_local_file_input_stream_read; 100 stream_class->skip = g_local_file_input_stream_skip; 101 stream_class->close_fn = g_local_file_input_stream_close; 102 file_stream_class->tell = g_local_file_input_stream_tell; 103 file_stream_class->can_seek = g_local_file_input_stream_can_seek; 104 file_stream_class->seek = g_local_file_input_stream_seek; 105 file_stream_class->query_info = g_local_file_input_stream_query_info; 106 } 107 108 static void 109 g_local_file_input_stream_init (GLocalFileInputStream *info) 110 { 111 info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info, 112 G_TYPE_LOCAL_FILE_INPUT_STREAM, 113 GLocalFileInputStreamPrivate); 114 } 115 116 /** 117 * g_local_file_input_stream_new: 118 * @fd: File Descriptor. 119 * 120 * Returns: #GFileInputStream for the given file descriptor. 121 **/ 122 GFileInputStream * 123 _g_local_file_input_stream_new (int fd) 124 { 125 GLocalFileInputStream *stream; 126 127 stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL); 128 stream->priv->fd = fd; 129 130 return G_FILE_INPUT_STREAM (stream); 131 } 132 133 static gssize 134 g_local_file_input_stream_read (GInputStream *stream, 135 void *buffer, 136 gsize count, 137 GCancellable *cancellable, 138 GError **error) 139 { 140 GLocalFileInputStream *file; 141 gssize res; 142 143 file = G_LOCAL_FILE_INPUT_STREAM (stream); 144 145 res = -1; 146 while (1) 147 { 148 if (g_cancellable_set_error_if_cancelled (cancellable, error)) 149 break; 150 res = read (file->priv->fd, buffer, count); 151 if (res == -1) 152 { 153 int errsv = errno; 154 155 if (errsv == EINTR) 156 continue; 157 158 g_set_error (error, G_IO_ERROR, 159 g_io_error_from_errno (errsv), 160 _("Error reading from file: %s"), 161 g_strerror (errsv)); 162 } 163 164 break; 165 } 166 167 return res; 168 } 169 170 static gssize 171 g_local_file_input_stream_skip (GInputStream *stream, 172 gsize count, 173 GCancellable *cancellable, 174 GError **error) 175 { 176 off_t res, start; 177 GLocalFileInputStream *file; 178 179 file = G_LOCAL_FILE_INPUT_STREAM (stream); 180 181 if (g_cancellable_set_error_if_cancelled (cancellable, error)) 182 return -1; 183 184 start = lseek (file->priv->fd, 0, SEEK_CUR); 185 if (start == -1) 186 { 187 int errsv = errno; 188 189 g_set_error (error, G_IO_ERROR, 190 g_io_error_from_errno (errsv), 191 _("Error seeking in file: %s"), 192 g_strerror (errsv)); 193 return -1; 194 } 195 196 res = lseek (file->priv->fd, count, SEEK_CUR); 197 if (res == -1) 198 { 199 int errsv = errno; 200 201 g_set_error (error, G_IO_ERROR, 202 g_io_error_from_errno (errsv), 203 _("Error seeking in file: %s"), 204 g_strerror (errsv)); 205 return -1; 206 } 207 208 return res - start; 209 } 210 211 static gboolean 212 g_local_file_input_stream_close (GInputStream *stream, 213 GCancellable *cancellable, 214 GError **error) 215 { 216 GLocalFileInputStream *file; 217 int res; 218 219 file = G_LOCAL_FILE_INPUT_STREAM (stream); 220 221 if (file->priv->fd == -1) 222 return TRUE; 223 224 while (1) 225 { 226 res = close (file->priv->fd); 227 if (res == -1) 228 { 229 int errsv = errno; 230 231 g_set_error (error, G_IO_ERROR, 232 g_io_error_from_errno (errsv), 233 _("Error closing file: %s"), 234 g_strerror (errsv)); 235 } 236 break; 237 } 238 239 return res != -1; 240 } 241 242 243 static goffset 244 g_local_file_input_stream_tell (GFileInputStream *stream) 245 { 246 GLocalFileInputStream *file; 247 off_t pos; 248 249 file = G_LOCAL_FILE_INPUT_STREAM (stream); 250 251 pos = lseek (file->priv->fd, 0, SEEK_CUR); 252 253 if (pos == (off_t)-1) 254 return 0; 255 256 return pos; 257 } 258 259 static gboolean 260 g_local_file_input_stream_can_seek (GFileInputStream *stream) 261 { 262 GLocalFileInputStream *file; 263 off_t pos; 264 265 file = G_LOCAL_FILE_INPUT_STREAM (stream); 266 267 pos = lseek (file->priv->fd, 0, SEEK_CUR); 268 269 if (pos == (off_t)-1 && errno == ESPIPE) 270 return FALSE; 271 272 return TRUE; 273 } 274 275 static int 276 seek_type_to_lseek (GSeekType type) 277 { 278 switch (type) 279 { 280 default: 281 case G_SEEK_CUR: 282 return SEEK_CUR; 283 284 case G_SEEK_SET: 285 return SEEK_SET; 286 287 case G_SEEK_END: 288 return SEEK_END; 289 } 290 } 291 292 static gboolean 293 g_local_file_input_stream_seek (GFileInputStream *stream, 294 goffset offset, 295 GSeekType type, 296 GCancellable *cancellable, 297 GError **error) 298 { 299 GLocalFileInputStream *file; 300 off_t pos; 301 302 file = G_LOCAL_FILE_INPUT_STREAM (stream); 303 304 pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type)); 305 306 if (pos == (off_t)-1) 307 { 308 int errsv = errno; 309 310 g_set_error (error, G_IO_ERROR, 311 g_io_error_from_errno (errsv), 312 _("Error seeking in file: %s"), 313 g_strerror (errsv)); 314 return FALSE; 315 } 316 317 return TRUE; 318 } 319 320 static GFileInfo * 321 g_local_file_input_stream_query_info (GFileInputStream *stream, 322 const char *attributes, 323 GCancellable *cancellable, 324 GError **error) 325 { 326 GLocalFileInputStream *file; 327 328 file = G_LOCAL_FILE_INPUT_STREAM (stream); 329 330 if (g_cancellable_set_error_if_cancelled (cancellable, error)) 331 return NULL; 332 333 return _g_local_file_info_get_from_fd (file->priv->fd, 334 attributes, 335 error); 336 } 337