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