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