Coverage Report

Created: 2025-06-13 06:55

/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
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General
18
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 <errno.h>
29
30
#include <glib.h>
31
#include <glib/gstdio.h>
32
#include "gcancellable.h"
33
#include "gioerror.h"
34
#include "glocalfileinputstream.h"
35
#include "glocalfileinfo.h"
36
#include "glibintl.h"
37
38
#ifdef G_OS_UNIX
39
#include <unistd.h>
40
#include "glib-unix.h"
41
#include "gfiledescriptorbased.h"
42
#endif
43
44
#ifdef G_OS_WIN32
45
#include <io.h>
46
#endif
47
48
struct _GLocalFileInputStreamPrivate {
49
  int fd;
50
  guint do_close : 1;
51
};
52
53
#ifdef G_OS_UNIX
54
static void       g_file_descriptor_based_iface_init   (GFileDescriptorBasedIface *iface);
55
#endif
56
57
#define g_local_file_input_stream_get_type _g_local_file_input_stream_get_type
58
#ifdef G_OS_UNIX
59
G_DEFINE_TYPE_WITH_CODE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM,
60
                         G_ADD_PRIVATE (GLocalFileInputStream)
61
       G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
62
            g_file_descriptor_based_iface_init))
63
#else
64
G_DEFINE_TYPE_WITH_CODE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INPUT_STREAM,
65
                         G_ADD_PRIVATE (GLocalFileInputStream))
66
#endif
67
68
static gssize     g_local_file_input_stream_read       (GInputStream      *stream,
69
              void              *buffer,
70
              gsize              count,
71
              GCancellable      *cancellable,
72
              GError           **error);
73
static gboolean   g_local_file_input_stream_close      (GInputStream      *stream,
74
              GCancellable      *cancellable,
75
              GError           **error);
76
static goffset    g_local_file_input_stream_tell       (GFileInputStream  *stream);
77
static gboolean   g_local_file_input_stream_can_seek   (GFileInputStream  *stream);
78
static gboolean   g_local_file_input_stream_seek       (GFileInputStream  *stream,
79
              goffset            offset,
80
              GSeekType          type,
81
              GCancellable      *cancellable,
82
              GError           **error);
83
static GFileInfo *g_local_file_input_stream_query_info (GFileInputStream  *stream,
84
              const char        *attributes,
85
              GCancellable      *cancellable,
86
              GError           **error);
87
#ifdef G_OS_UNIX
88
static int        g_local_file_input_stream_get_fd     (GFileDescriptorBased *stream);
89
#endif
90
91
void
92
_g_local_file_input_stream_set_do_close (GLocalFileInputStream *in,
93
            gboolean do_close)
94
0
{
95
0
  in->priv->do_close = do_close;
96
0
}
97
98
static void
99
g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass)
100
0
{
101
0
  GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
102
0
  GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
103
104
0
  stream_class->read_fn = g_local_file_input_stream_read;
105
0
  stream_class->close_fn = g_local_file_input_stream_close;
106
0
  file_stream_class->tell = g_local_file_input_stream_tell;
107
0
  file_stream_class->can_seek = g_local_file_input_stream_can_seek;
108
0
  file_stream_class->seek = g_local_file_input_stream_seek;
109
0
  file_stream_class->query_info = g_local_file_input_stream_query_info;
110
0
}
111
112
#ifdef G_OS_UNIX
113
static void
114
g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
115
0
{
116
0
  iface->get_fd = g_local_file_input_stream_get_fd;
117
0
}
118
#endif
119
120
static void
121
g_local_file_input_stream_init (GLocalFileInputStream *info)
122
0
{
123
0
  info->priv = g_local_file_input_stream_get_instance_private (info);
124
0
  info->priv->do_close = TRUE;
125
0
}
126
127
GFileInputStream *
128
_g_local_file_input_stream_new (int fd)
129
0
{
130
0
  GLocalFileInputStream *stream;
131
132
0
  stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL);
133
0
  stream->priv->fd = fd;
134
  
135
0
  return G_FILE_INPUT_STREAM (stream);
136
0
}
137
138
static gssize
139
g_local_file_input_stream_read (GInputStream  *stream,
140
        void          *buffer,
141
        gsize          count,
142
        GCancellable  *cancellable,
143
        GError       **error)
144
0
{
145
0
  GLocalFileInputStream *file;
146
0
  gssize res;
147
148
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
149
150
0
  res = -1;
151
0
  while (1)
152
0
    {
153
0
      if (g_cancellable_set_error_if_cancelled (cancellable, error))
154
0
  break;
155
0
      res = read (file->priv->fd, buffer, count);
156
0
      if (res == -1)
157
0
  {
158
0
          int errsv = errno;
159
160
0
    if (errsv == EINTR)
161
0
      continue;
162
    
163
0
    g_set_error (error, G_IO_ERROR,
164
0
           g_io_error_from_errno (errsv),
165
0
           _("Error reading from file: %s"),
166
0
           g_strerror (errsv));
167
0
  }
168
      
169
0
      break;
170
0
    }
171
  
172
0
  return res;
173
0
}
174
175
static gboolean
176
g_local_file_input_stream_close (GInputStream  *stream,
177
         GCancellable  *cancellable,
178
         GError       **error)
179
0
{
180
0
  GLocalFileInputStream *file;
181
182
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
183
184
0
  if (!file->priv->do_close)
185
0
    return TRUE;
186
187
0
  if (file->priv->fd == -1)
188
0
    return TRUE;
189
190
0
  if (!g_close (file->priv->fd, NULL))
191
0
    {
192
0
      int errsv = errno;
193
      
194
0
      g_set_error (error, G_IO_ERROR,
195
0
                   g_io_error_from_errno (errsv),
196
0
                   _("Error closing file: %s"),
197
0
                   g_strerror (errsv));
198
0
      return FALSE;
199
0
    }
200
201
0
  return TRUE;
202
0
}
203
204
205
static goffset
206
g_local_file_input_stream_tell (GFileInputStream *stream)
207
0
{
208
0
  GLocalFileInputStream *file;
209
0
  off_t pos;
210
211
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
212
  
213
0
  pos = lseek (file->priv->fd, 0, SEEK_CUR);
214
215
0
  if (pos == (off_t)-1)
216
0
    return 0;
217
  
218
0
  return pos;
219
0
}
220
221
static gboolean
222
g_local_file_input_stream_can_seek (GFileInputStream *stream)
223
0
{
224
0
  GLocalFileInputStream *file;
225
0
  off_t pos;
226
227
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
228
  
229
0
  pos = lseek (file->priv->fd, 0, SEEK_CUR);
230
231
0
  if (pos == (off_t)-1 && errno == ESPIPE)
232
0
    return FALSE;
233
  
234
0
  return TRUE;
235
0
}
236
237
static int
238
seek_type_to_lseek (GSeekType type)
239
0
{
240
0
  switch (type)
241
0
    {
242
0
    default:
243
0
    case G_SEEK_CUR:
244
0
      return SEEK_CUR;
245
      
246
0
    case G_SEEK_SET:
247
0
      return SEEK_SET;
248
      
249
0
    case G_SEEK_END:
250
0
      return SEEK_END;
251
0
    }
252
0
}
253
254
static gboolean
255
g_local_file_input_stream_seek (GFileInputStream  *stream,
256
        goffset            offset,
257
        GSeekType          type,
258
        GCancellable      *cancellable,
259
        GError           **error)
260
0
{
261
0
  GLocalFileInputStream *file;
262
0
  off_t pos;
263
264
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
265
266
0
  pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
267
268
0
  if (pos == (off_t)-1)
269
0
    {
270
0
      int errsv = errno;
271
272
0
      g_set_error (error, G_IO_ERROR,
273
0
       g_io_error_from_errno (errsv),
274
0
       _("Error seeking in file: %s"),
275
0
       g_strerror (errsv));
276
0
      return FALSE;
277
0
    }
278
  
279
0
  return TRUE;
280
0
}
281
282
static GFileInfo *
283
g_local_file_input_stream_query_info (GFileInputStream  *stream,
284
              const char        *attributes,
285
              GCancellable      *cancellable,
286
              GError           **error)
287
0
{
288
0
  GLocalFileInputStream *file;
289
290
0
  file = G_LOCAL_FILE_INPUT_STREAM (stream);
291
292
0
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
293
0
    return NULL;
294
  
295
0
  return _g_local_file_info_get_from_fd (file->priv->fd,
296
0
           attributes,
297
0
           error);
298
0
}
299
300
#ifdef G_OS_UNIX
301
static int
302
g_local_file_input_stream_get_fd (GFileDescriptorBased *fd_based)
303
0
{
304
0
  GLocalFileInputStream *stream = G_LOCAL_FILE_INPUT_STREAM (fd_based);
305
0
  return stream->priv->fd;
306
0
}
307
#endif