Coverage Report

Created: 2025-07-01 07:09

/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 gboolean   g_local_file_input_stream_close      (GInputStream      *stream,
72
              GCancellable      *cancellable,
73
              GError           **error);
74
static goffset    g_local_file_input_stream_tell       (GFileInputStream  *stream);
75
static gboolean   g_local_file_input_stream_can_seek   (GFileInputStream  *stream);
76
static gboolean   g_local_file_input_stream_seek       (GFileInputStream  *stream,
77
              goffset            offset,
78
              GSeekType          type,
79
              GCancellable      *cancellable,
80
              GError           **error);
81
static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream  *stream,
82
              const char        *attributes,
83
              GCancellable      *cancellable,
84
              GError           **error);
85
#ifdef G_OS_UNIX
86
static int        g_local_file_input_stream_get_fd     (GFileDescriptorBased *stream);
87
#endif
88
89
void
90
_g_local_file_input_stream_set_do_close (GLocalFileInputStream *in,
91
            gboolean do_close)
92
0
{
93
0
  in->priv->do_close = do_close;
94
0
}
95
96
static void
97
g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass)
98
0
{
99
0
  GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
100
0
  GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
101
102
0
  stream_class->read_fn = g_local_file_input_stream_read;
103
0
  stream_class->close_fn = g_local_file_input_stream_close;
104
0
  file_stream_class->tell = g_local_file_input_stream_tell;
105
0
  file_stream_class->can_seek = g_local_file_input_stream_can_seek;
106
0
  file_stream_class->seek = g_local_file_input_stream_seek;
107
0
  file_stream_class->query_info = g_local_file_input_stream_query_info;
108
0
}
109
110
#ifdef G_OS_UNIX
111
static void
112
g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
113
0
{
114
0
  iface->get_fd = g_local_file_input_stream_get_fd;
115
0
}
116
#endif
117
118
static void
119
g_local_file_input_stream_init (GLocalFileInputStream *info)
120
0
{
121
0
  info->priv = g_local_file_input_stream_get_instance_private (info);
122
0
  info->priv->do_close = TRUE;
123
0
}
124
125
GFileInputStream *
126
_g_local_file_input_stream_new (int fd)
127
0
{
128
0
  GLocalFileInputStream *stream;
129
130
0
  stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL);
131
0
  stream->priv->fd = fd;
132
  
133
0
  return G_FILE_INPUT_STREAM (stream);
134
0
}
135
136
static gssize
137
g_local_file_input_stream_read (GInputStream  *stream,
138
        void          *buffer,
139
        gsize          count,
140
        GCancellable  *cancellable,
141
        GError       **error)
142
0
{
143
0
  GLocalFileInputStream *file;
144
0
  gssize res;
145
146
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
147
148
0
  res = -1;
149
0
  while (1)
150
0
    {
151
0
      if (g_cancellable_set_error_if_cancelled (cancellable, error))
152
0
  break;
153
0
      res = read (file->priv->fd, buffer, count);
154
0
      if (res == -1)
155
0
  {
156
0
          int errsv = errno;
157
158
0
    if (errsv == EINTR)
159
0
      continue;
160
    
161
0
    g_set_error (error, G_IO_ERROR,
162
0
           g_io_error_from_errno (errsv),
163
0
           _("Error reading from file: %s"),
164
0
           g_strerror (errsv));
165
0
  }
166
      
167
0
      break;
168
0
    }
169
  
170
0
  return res;
171
0
}
172
173
static gboolean
174
g_local_file_input_stream_close (GInputStream  *stream,
175
         GCancellable  *cancellable,
176
         GError       **error)
177
0
{
178
0
  GLocalFileInputStream *file;
179
180
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
181
182
0
  if (!file->priv->do_close)
183
0
    return TRUE;
184
185
0
  if (file->priv->fd == -1)
186
0
    return TRUE;
187
188
0
  if (!g_close (file->priv->fd, NULL))
189
0
    {
190
0
      int errsv = errno;
191
      
192
0
      g_set_error (error, G_IO_ERROR,
193
0
                   g_io_error_from_errno (errsv),
194
0
                   _("Error closing file: %s"),
195
0
                   g_strerror (errsv));
196
0
      return FALSE;
197
0
    }
198
199
0
  return TRUE;
200
0
}
201
202
203
static goffset
204
g_local_file_input_stream_tell (GFileInputStream *stream)
205
0
{
206
0
  GLocalFileInputStream *file;
207
0
  off_t pos;
208
209
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
210
  
211
0
  pos = lseek (file->priv->fd, 0, SEEK_CUR);
212
213
0
  if (pos == (off_t)-1)
214
0
    return 0;
215
  
216
0
  return pos;
217
0
}
218
219
static gboolean
220
g_local_file_input_stream_can_seek (GFileInputStream *stream)
221
0
{
222
0
  GLocalFileInputStream *file;
223
0
  off_t pos;
224
225
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
226
  
227
0
  pos = lseek (file->priv->fd, 0, SEEK_CUR);
228
229
0
  if (pos == (off_t)-1 && errno == ESPIPE)
230
0
    return FALSE;
231
  
232
0
  return TRUE;
233
0
}
234
235
static int
236
seek_type_to_lseek (GSeekType type)
237
0
{
238
0
  switch (type)
239
0
    {
240
0
    default:
241
0
    case G_SEEK_CUR:
242
0
      return SEEK_CUR;
243
      
244
0
    case G_SEEK_SET:
245
0
      return SEEK_SET;
246
      
247
0
    case G_SEEK_END:
248
0
      return SEEK_END;
249
0
    }
250
0
}
251
252
static gboolean
253
g_local_file_input_stream_seek (GFileInputStream  *stream,
254
        goffset            offset,
255
        GSeekType          type,
256
        GCancellable      *cancellable,
257
        GError           **error)
258
0
{
259
0
  GLocalFileInputStream *file;
260
0
  off_t pos;
261
262
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
263
264
0
  pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
265
266
0
  if (pos == (off_t)-1)
267
0
    {
268
0
      int errsv = errno;
269
270
0
      g_set_error (error, G_IO_ERROR,
271
0
       g_io_error_from_errno (errsv),
272
0
       _("Error seeking in file: %s"),
273
0
       g_strerror (errsv));
274
0
      return FALSE;
275
0
    }
276
  
277
0
  return TRUE;
278
0
}
279
280
static GFileInfo *
281
g_local_file_input_stream_query_info (GFileInputStream  *stream,
282
              const char        *attributes,
283
              GCancellable      *cancellable,
284
              GError           **error)
285
0
{
286
0
  GLocalFileInputStream *file;
287
288
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
289
290
0
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
291
0
    return NULL;
292
  
293
0
  return _g_local_file_info_get_from_fd (file->priv->fd,
294
0
           attributes,
295
0
           error);
296
0
}
297
298
#ifdef G_OS_UNIX
299
static int
300
g_local_file_input_stream_get_fd (GFileDescriptorBased *fd_based)
301
0
{
302
0
  GLocalFileInputStream *stream = G_LOCAL_FILE_INPUT_STREAM (fd_based);
303
0
  return stream->priv->fd;
304
0
}
305
#endif