a1aa00b43e04fa0dc46893d7d5e304bcd9e6838f
[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 #define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type
41 G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM);
42
43 struct _GLocalFileInputStreamPrivate {
44   int fd;
45 };
46
47 static gssize     g_local_file_input_stream_read       (GInputStream      *stream,
48                                                         void              *buffer,
49                                                         gsize              count,
50                                                         GCancellable      *cancellable,
51                                                         GError           **error);
52 static gssize     g_local_file_input_stream_skip       (GInputStream      *stream,
53                                                         gsize              count,
54                                                         GCancellable      *cancellable,
55                                                         GError           **error);
56 static gboolean   g_local_file_input_stream_close      (GInputStream      *stream,
57                                                         GCancellable      *cancellable,
58                                                         GError           **error);
59 static goffset    g_local_file_input_stream_tell       (GFileInputStream  *stream);
60 static gboolean   g_local_file_input_stream_can_seek   (GFileInputStream  *stream);
61 static gboolean   g_local_file_input_stream_seek       (GFileInputStream  *stream,
62                                                         goffset            offset,
63                                                         GSeekType          type,
64                                                         GCancellable      *cancellable,
65                                                         GError           **error);
66 static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream  *stream,
67                                                         char              *attributes,
68                                                         GCancellable      *cancellable,
69                                                         GError           **error);
70
71 static void
72 g_local_file_input_stream_finalize (GObject *object)
73 {
74   GLocalFileInputStream *file;
75   
76   file = G_LOCAL_FILE_INPUT_STREAM (object);
77   
78   if (G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize)
79     (*G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize) (object);
80 }
81
82 static void
83 g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass)
84 {
85   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
86   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
87   GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
88   
89   g_type_class_add_private (klass, sizeof (GLocalFileInputStreamPrivate));
90   
91   gobject_class->finalize = g_local_file_input_stream_finalize;
92
93   stream_class->read = g_local_file_input_stream_read;
94   stream_class->skip = g_local_file_input_stream_skip;
95   stream_class->close = g_local_file_input_stream_close;
96   file_stream_class->tell = g_local_file_input_stream_tell;
97   file_stream_class->can_seek = g_local_file_input_stream_can_seek;
98   file_stream_class->seek = g_local_file_input_stream_seek;
99   file_stream_class->query_info = g_local_file_input_stream_query_info;
100 }
101
102 static void
103 g_local_file_input_stream_init (GLocalFileInputStream *info)
104 {
105   info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info,
106                                             G_TYPE_LOCAL_FILE_INPUT_STREAM,
107                                             GLocalFileInputStreamPrivate);
108 }
109
110 /**
111  * g_local_file_input_stream_new:
112  * @fd: File Descriptor.
113  * 
114  * Returns: #GFileInputStream for the given file descriptor.
115  **/
116 GFileInputStream *
117 _g_local_file_input_stream_new (int fd)
118 {
119   GLocalFileInputStream *stream;
120
121   stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL);
122   stream->priv->fd = fd;
123   
124   return G_FILE_INPUT_STREAM (stream);
125 }
126
127 static gssize
128 g_local_file_input_stream_read (GInputStream  *stream,
129                                 void          *buffer,
130                                 gsize          count,
131                                 GCancellable  *cancellable,
132                                 GError       **error)
133 {
134   GLocalFileInputStream *file;
135   gssize res;
136
137   file = G_LOCAL_FILE_INPUT_STREAM (stream);
138
139   res = -1;
140   while (1)
141     {
142       if (g_cancellable_set_error_if_cancelled (cancellable, error))
143         break;
144       res = read (file->priv->fd, buffer, count);
145       if (res == -1)
146         {
147           if (errno == EINTR)
148             continue;
149           
150           g_set_error (error, G_IO_ERROR,
151                        g_io_error_from_errno (errno),
152                        _("Error reading from file: %s"),
153                        g_strerror (errno));
154         }
155       
156       break;
157     }
158   
159   return res;
160 }
161
162 static gssize
163 g_local_file_input_stream_skip (GInputStream  *stream,
164                                 gsize          count,
165                                 GCancellable  *cancellable,
166                                 GError       **error)
167 {
168   off_t res, start;
169   GLocalFileInputStream *file;
170
171   file = G_LOCAL_FILE_INPUT_STREAM (stream);
172   
173   if (g_cancellable_set_error_if_cancelled (cancellable, error))
174     return -1;
175   
176   start = lseek (file->priv->fd, 0, SEEK_CUR);
177   if (start == -1)
178     {
179       g_set_error (error, G_IO_ERROR,
180                    g_io_error_from_errno (errno),
181                    _("Error seeking in file: %s"),
182                    g_strerror (errno));
183       return -1;
184     }
185   
186   res = lseek (file->priv->fd, count, SEEK_CUR);
187   if (res == -1)
188     {
189       g_set_error (error, G_IO_ERROR,
190                    g_io_error_from_errno (errno),
191                    _("Error seeking in file: %s"),
192                    g_strerror (errno));
193       return -1;
194     }
195
196   return res - start;
197 }
198
199 static gboolean
200 g_local_file_input_stream_close (GInputStream  *stream,
201                                  GCancellable  *cancellable,
202                                  GError       **error)
203 {
204   GLocalFileInputStream *file;
205   int res;
206
207   file = G_LOCAL_FILE_INPUT_STREAM (stream);
208
209   if (file->priv->fd == -1)
210     return TRUE;
211
212   while (1)
213     {
214       res = close (file->priv->fd);
215       if (res == -1)
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       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 }