Coverage Report

Created: 2018-09-25 13:52

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