gio/ docs/reference/gio Merged gio-standalone into glib.
[platform/upstream/glib.git] / gio / glocalfileinputstream.c
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@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include <glib.h>
32 #include <glib/gstdio.h>
33 #include "gioerror.h"
34 #include "glocalfileinputstream.h"
35 #include "glocalfileinfo.h"
36 #include "glibintl.h"
37
38
39 G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM);
40
41 struct _GLocalFileInputStreamPrivate {
42   int fd;
43 };
44
45 static gssize     g_local_file_input_stream_read       (GInputStream      *stream,
46                                                         void              *buffer,
47                                                         gsize              count,
48                                                         GCancellable      *cancellable,
49                                                         GError           **error);
50 static gssize     g_local_file_input_stream_skip       (GInputStream      *stream,
51                                                         gsize              count,
52                                                         GCancellable      *cancellable,
53                                                         GError           **error);
54 static gboolean   g_local_file_input_stream_close      (GInputStream      *stream,
55                                                         GCancellable      *cancellable,
56                                                         GError           **error);
57 static goffset    g_local_file_input_stream_tell       (GFileInputStream  *stream);
58 static gboolean   g_local_file_input_stream_can_seek   (GFileInputStream  *stream);
59 static gboolean   g_local_file_input_stream_seek       (GFileInputStream  *stream,
60                                                         goffset            offset,
61                                                         GSeekType          type,
62                                                         GCancellable      *cancellable,
63                                                         GError           **error);
64 static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream  *stream,
65                                                         char              *attributes,
66                                                         GCancellable      *cancellable,
67                                                         GError           **error);
68
69 static void
70 g_local_file_input_stream_finalize (GObject *object)
71 {
72   GLocalFileInputStream *file;
73   
74   file = G_LOCAL_FILE_INPUT_STREAM (object);
75   
76   if (G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize)
77     (*G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize) (object);
78 }
79
80 static void
81 g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass)
82 {
83   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
84   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
85   GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
86   
87   g_type_class_add_private (klass, sizeof (GLocalFileInputStreamPrivate));
88   
89   gobject_class->finalize = g_local_file_input_stream_finalize;
90
91   stream_class->read = g_local_file_input_stream_read;
92   stream_class->skip = g_local_file_input_stream_skip;
93   stream_class->close = g_local_file_input_stream_close;
94   file_stream_class->tell = g_local_file_input_stream_tell;
95   file_stream_class->can_seek = g_local_file_input_stream_can_seek;
96   file_stream_class->seek = g_local_file_input_stream_seek;
97   file_stream_class->query_info = g_local_file_input_stream_query_info;
98 }
99
100 static void
101 g_local_file_input_stream_init (GLocalFileInputStream *info)
102 {
103   info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info,
104                                             G_TYPE_LOCAL_FILE_INPUT_STREAM,
105                                             GLocalFileInputStreamPrivate);
106 }
107
108 /**
109  * g_local_file_input_stream_new:
110  * @fd: File Descriptor.
111  * 
112  * Returns: #GFileInputStream for the given file descriptor.
113  **/
114 GFileInputStream *
115 g_local_file_input_stream_new (int fd)
116 {
117   GLocalFileInputStream *stream;
118
119   stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL);
120   stream->priv->fd = fd;
121   
122   return G_FILE_INPUT_STREAM (stream);
123 }
124
125 static gssize
126 g_local_file_input_stream_read (GInputStream *stream,
127                                 void         *buffer,
128                                 gsize         count,
129                                 GCancellable *cancellable,
130                                 GError      **error)
131 {
132   GLocalFileInputStream *file;
133   gssize res;
134
135   file = G_LOCAL_FILE_INPUT_STREAM (stream);
136
137   res = -1;
138   while (1)
139     {
140       if (g_cancellable_set_error_if_cancelled (cancellable, error))
141         break;
142       res = read (file->priv->fd, buffer, count);
143       if (res == -1)
144         {
145           if (errno == EINTR)
146             continue;
147           
148           g_set_error (error, G_IO_ERROR,
149                        g_io_error_from_errno (errno),
150                        _("Error reading from file: %s"),
151                        g_strerror (errno));
152         }
153       
154       break;
155     }
156   
157   return res;
158 }
159
160 static gssize
161 g_local_file_input_stream_skip (GInputStream *stream,
162                                 gsize         count,
163                                 GCancellable *cancellable,
164                                 GError      **error)
165 {
166   off_t res, start;
167   GLocalFileInputStream *file;
168
169   file = G_LOCAL_FILE_INPUT_STREAM (stream);
170   
171   if (g_cancellable_set_error_if_cancelled (cancellable, error))
172     return -1;
173   
174   start = lseek (file->priv->fd, 0, SEEK_CUR);
175   if (start == -1)
176     {
177       g_set_error (error, G_IO_ERROR,
178                    g_io_error_from_errno (errno),
179                    _("Error seeking in file: %s"),
180                    g_strerror (errno));
181       return -1;
182     }
183   
184   res = lseek (file->priv->fd, count, SEEK_CUR);
185   if (res == -1)
186     {
187       g_set_error (error, G_IO_ERROR,
188                    g_io_error_from_errno (errno),
189                    _("Error seeking in file: %s"),
190                    g_strerror (errno));
191       return -1;
192     }
193
194   return res - start;
195 }
196
197 static gboolean
198 g_local_file_input_stream_close (GInputStream *stream,
199                                  GCancellable *cancellable,
200                                  GError      **error)
201 {
202   GLocalFileInputStream *file;
203   int res;
204
205   file = G_LOCAL_FILE_INPUT_STREAM (stream);
206
207   if (file->priv->fd == -1)
208     return TRUE;
209
210   while (1)
211     {
212       res = close (file->priv->fd);
213       if (res == -1)
214         {
215           g_set_error (error, G_IO_ERROR,
216                        g_io_error_from_errno (errno),
217                        _("Error closing file: %s"),
218                        g_strerror (errno));
219         }
220       break;
221     }
222
223   return res != -1;
224 }
225
226
227 static goffset
228 g_local_file_input_stream_tell (GFileInputStream *stream)
229 {
230   GLocalFileInputStream *file;
231   off_t pos;
232
233   file = G_LOCAL_FILE_INPUT_STREAM (stream);
234   
235   pos = lseek (file->priv->fd, 0, SEEK_CUR);
236
237   if (pos == (off_t)-1)
238     return 0;
239   
240   return pos;
241 }
242
243 static gboolean
244 g_local_file_input_stream_can_seek (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       errno == ESPIPE)
255     return FALSE;
256   
257   return TRUE;
258 }
259
260 static int
261 seek_type_to_lseek (GSeekType type)
262 {
263   switch (type)
264     {
265     default:
266     case G_SEEK_CUR:
267       return SEEK_CUR;
268       
269     case G_SEEK_SET:
270       return SEEK_SET;
271       
272     case G_SEEK_END:
273       return SEEK_END;
274     }
275 }
276
277 static gboolean
278 g_local_file_input_stream_seek (GFileInputStream     *stream,
279                                 goffset               offset,
280                                 GSeekType             type,
281                                 GCancellable         *cancellable,
282                                 GError              **error)
283 {
284   GLocalFileInputStream *file;
285   off_t pos;
286
287   file = G_LOCAL_FILE_INPUT_STREAM (stream);
288
289   pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
290
291   if (pos == (off_t)-1)
292     {
293       g_set_error (error, G_IO_ERROR,
294                    g_io_error_from_errno (errno),
295                    _("Error seeking in file: %s"),
296                    g_strerror (errno));
297       return FALSE;
298     }
299   
300   return TRUE;
301 }
302
303 static GFileInfo *
304 g_local_file_input_stream_query_info (GFileInputStream     *stream,
305                                       char                 *attributes,
306                                       GCancellable         *cancellable,
307                                       GError              **error)
308 {
309   GLocalFileInputStream *file;
310
311   file = G_LOCAL_FILE_INPUT_STREAM (stream);
312
313   if (g_cancellable_set_error_if_cancelled (cancellable, error))
314     return NULL;
315   
316   return _g_local_file_info_get_from_fd (file->priv->fd,
317                                          attributes,
318                                          error);
319 }