[gio compiles and links on win32, not sure how much already works] ifdefed
[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 "gioerror.h"
36 #include "glocalfileinputstream.h"
37 #include "glocalfileinfo.h"
38 #include "glibintl.h"
39
40 #ifdef G_OS_WIN32
41 #include <io.h>
42 #endif
43
44 #include "gioalias.h"
45
46 #define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type
47 G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM);
48
49 struct _GLocalFileInputStreamPrivate {
50   int fd;
51 };
52
53 static gssize     g_local_file_input_stream_read       (GInputStream      *stream,
54                                                         void              *buffer,
55                                                         gsize              count,
56                                                         GCancellable      *cancellable,
57                                                         GError           **error);
58 static gssize     g_local_file_input_stream_skip       (GInputStream      *stream,
59                                                         gsize              count,
60                                                         GCancellable      *cancellable,
61                                                         GError           **error);
62 static gboolean   g_local_file_input_stream_close      (GInputStream      *stream,
63                                                         GCancellable      *cancellable,
64                                                         GError           **error);
65 static goffset    g_local_file_input_stream_tell       (GFileInputStream  *stream);
66 static gboolean   g_local_file_input_stream_can_seek   (GFileInputStream  *stream);
67 static gboolean   g_local_file_input_stream_seek       (GFileInputStream  *stream,
68                                                         goffset            offset,
69                                                         GSeekType          type,
70                                                         GCancellable      *cancellable,
71                                                         GError           **error);
72 static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream  *stream,
73                                                         char              *attributes,
74                                                         GCancellable      *cancellable,
75                                                         GError           **error);
76
77 static void
78 g_local_file_input_stream_finalize (GObject *object)
79 {
80   GLocalFileInputStream *file;
81   
82   file = G_LOCAL_FILE_INPUT_STREAM (object);
83   
84   if (G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize)
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           if (errno == EINTR)
154             continue;
155           
156           g_set_error (error, G_IO_ERROR,
157                        g_io_error_from_errno (errno),
158                        _("Error reading from file: %s"),
159                        g_strerror (errno));
160         }
161       
162       break;
163     }
164   
165   return res;
166 }
167
168 static gssize
169 g_local_file_input_stream_skip (GInputStream  *stream,
170                                 gsize          count,
171                                 GCancellable  *cancellable,
172                                 GError       **error)
173 {
174   off_t res, start;
175   GLocalFileInputStream *file;
176
177   file = G_LOCAL_FILE_INPUT_STREAM (stream);
178   
179   if (g_cancellable_set_error_if_cancelled (cancellable, error))
180     return -1;
181   
182   start = lseek (file->priv->fd, 0, SEEK_CUR);
183   if (start == -1)
184     {
185       g_set_error (error, G_IO_ERROR,
186                    g_io_error_from_errno (errno),
187                    _("Error seeking in file: %s"),
188                    g_strerror (errno));
189       return -1;
190     }
191   
192   res = lseek (file->priv->fd, count, SEEK_CUR);
193   if (res == -1)
194     {
195       g_set_error (error, G_IO_ERROR,
196                    g_io_error_from_errno (errno),
197                    _("Error seeking in file: %s"),
198                    g_strerror (errno));
199       return -1;
200     }
201
202   return res - start;
203 }
204
205 static gboolean
206 g_local_file_input_stream_close (GInputStream  *stream,
207                                  GCancellable  *cancellable,
208                                  GError       **error)
209 {
210   GLocalFileInputStream *file;
211   int res;
212
213   file = G_LOCAL_FILE_INPUT_STREAM (stream);
214
215   if (file->priv->fd == -1)
216     return TRUE;
217
218   while (1)
219     {
220       res = close (file->priv->fd);
221       if (res == -1)
222         g_set_error (error, G_IO_ERROR,
223                      g_io_error_from_errno (errno),
224                      _("Error closing file: %s"),
225                      g_strerror (errno));
226       break;
227     }
228
229   return res != -1;
230 }
231
232
233 static goffset
234 g_local_file_input_stream_tell (GFileInputStream *stream)
235 {
236   GLocalFileInputStream *file;
237   off_t pos;
238
239   file = G_LOCAL_FILE_INPUT_STREAM (stream);
240   
241   pos = lseek (file->priv->fd, 0, SEEK_CUR);
242
243   if (pos == (off_t)-1)
244     return 0;
245   
246   return pos;
247 }
248
249 static gboolean
250 g_local_file_input_stream_can_seek (GFileInputStream *stream)
251 {
252   GLocalFileInputStream *file;
253   off_t pos;
254
255   file = G_LOCAL_FILE_INPUT_STREAM (stream);
256   
257   pos = lseek (file->priv->fd, 0, SEEK_CUR);
258
259   if (pos == (off_t)-1 &&
260       errno == ESPIPE)
261     return FALSE;
262   
263   return TRUE;
264 }
265
266 static int
267 seek_type_to_lseek (GSeekType type)
268 {
269   switch (type)
270     {
271     default:
272     case G_SEEK_CUR:
273       return SEEK_CUR;
274       
275     case G_SEEK_SET:
276       return SEEK_SET;
277       
278     case G_SEEK_END:
279       return SEEK_END;
280     }
281 }
282
283 static gboolean
284 g_local_file_input_stream_seek (GFileInputStream  *stream,
285                                 goffset            offset,
286                                 GSeekType          type,
287                                 GCancellable      *cancellable,
288                                 GError           **error)
289 {
290   GLocalFileInputStream *file;
291   off_t pos;
292
293   file = G_LOCAL_FILE_INPUT_STREAM (stream);
294
295   pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
296
297   if (pos == (off_t)-1)
298     {
299       g_set_error (error, G_IO_ERROR,
300                    g_io_error_from_errno (errno),
301                    _("Error seeking in file: %s"),
302                    g_strerror (errno));
303       return FALSE;
304     }
305   
306   return TRUE;
307 }
308
309 static GFileInfo *
310 g_local_file_input_stream_query_info (GFileInputStream  *stream,
311                                       char              *attributes,
312                                       GCancellable      *cancellable,
313                                       GError           **error)
314 {
315   GLocalFileInputStream *file;
316
317   file = G_LOCAL_FILE_INPUT_STREAM (stream);
318
319   if (g_cancellable_set_error_if_cancelled (cancellable, error))
320     return NULL;
321   
322   return _g_local_file_info_get_from_fd (file->priv->fd,
323                                          attributes,
324                                          error);
325 }