Coverage Report

Created: 2025-07-12 06:25

/src/rauc/subprojects/glib-2.76.5/gio/gfileinputstream.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 <glib.h>
26
#include <gfileinputstream.h>
27
#include <gseekable.h>
28
#include "gcancellable.h"
29
#include "gasyncresult.h"
30
#include "gtask.h"
31
#include "gioerror.h"
32
#include "glibintl.h"
33
34
35
/**
36
 * SECTION:gfileinputstream
37
 * @short_description: File input streaming operations
38
 * @include: gio/gio.h
39
 * @see_also: #GInputStream, #GDataInputStream, #GSeekable
40
 *
41
 * GFileInputStream provides input streams that take their
42
 * content from a file.
43
 *
44
 * GFileInputStream implements #GSeekable, which allows the input 
45
 * stream to jump to arbitrary positions in the file, provided the 
46
 * filesystem of the file allows it. To find the position of a file
47
 * input stream, use g_seekable_tell(). To find out if a file input
48
 * stream supports seeking, use g_seekable_can_seek().
49
 * To position a file input stream, use g_seekable_seek().
50
 **/
51
52
static void       g_file_input_stream_seekable_iface_init    (GSeekableIface       *iface);
53
static goffset    g_file_input_stream_seekable_tell          (GSeekable            *seekable);
54
static gboolean   g_file_input_stream_seekable_can_seek      (GSeekable            *seekable);
55
static gboolean   g_file_input_stream_seekable_seek          (GSeekable            *seekable,
56
                    goffset               offset,
57
                    GSeekType             type,
58
                    GCancellable         *cancellable,
59
                    GError              **error);
60
static gboolean   g_file_input_stream_seekable_can_truncate  (GSeekable            *seekable);
61
static gboolean   g_file_input_stream_seekable_truncate      (GSeekable            *seekable,
62
                    goffset               offset,
63
                    GCancellable         *cancellable,
64
                    GError              **error);
65
static void       g_file_input_stream_real_query_info_async  (GFileInputStream     *stream,
66
                    const char           *attributes,
67
                    int                   io_priority,
68
                    GCancellable         *cancellable,
69
                    GAsyncReadyCallback   callback,
70
                    gpointer              user_data);
71
static GFileInfo *g_file_input_stream_real_query_info_finish (GFileInputStream     *stream,
72
                    GAsyncResult         *result,
73
                    GError              **error);
74
75
76
struct _GFileInputStreamPrivate {
77
  GAsyncReadyCallback outstanding_callback;
78
};
79
80
G_DEFINE_TYPE_WITH_CODE (GFileInputStream, g_file_input_stream, G_TYPE_INPUT_STREAM,
81
                         G_ADD_PRIVATE (GFileInputStream)
82
       G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
83
            g_file_input_stream_seekable_iface_init))
84
85
static void
86
g_file_input_stream_class_init (GFileInputStreamClass *klass)
87
1
{
88
1
  klass->query_info_async = g_file_input_stream_real_query_info_async;
89
1
  klass->query_info_finish = g_file_input_stream_real_query_info_finish;
90
1
}
91
92
static void
93
g_file_input_stream_seekable_iface_init (GSeekableIface *iface)
94
1
{
95
1
  iface->tell = g_file_input_stream_seekable_tell;
96
1
  iface->can_seek = g_file_input_stream_seekable_can_seek;
97
1
  iface->seek = g_file_input_stream_seekable_seek;
98
1
  iface->can_truncate = g_file_input_stream_seekable_can_truncate;
99
1
  iface->truncate_fn = g_file_input_stream_seekable_truncate;
100
1
}
101
102
static void
103
g_file_input_stream_init (GFileInputStream *stream)
104
4.77k
{
105
4.77k
  stream->priv = g_file_input_stream_get_instance_private (stream);
106
4.77k
}
107
108
/**
109
 * g_file_input_stream_query_info:
110
 * @stream: a #GFileInputStream.
111
 * @attributes: a file attribute query string.
112
 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. 
113
 * @error: a #GError location to store the error occurring, or %NULL to 
114
 * ignore.
115
 *
116
 * Queries a file input stream the given @attributes. This function blocks 
117
 * while querying the stream. For the asynchronous (non-blocking) version 
118
 * of this function, see g_file_input_stream_query_info_async(). While the 
119
 * stream is blocked, the stream will set the pending flag internally, and 
120
 * any other operations on the stream will fail with %G_IO_ERROR_PENDING.
121
 *
122
 * Returns: (transfer full): a #GFileInfo, or %NULL on error.
123
 **/
124
GFileInfo *
125
g_file_input_stream_query_info (GFileInputStream  *stream,
126
                                const char        *attributes,
127
                                GCancellable      *cancellable,
128
                                GError           **error)
129
4.77k
{
130
4.77k
  GFileInputStreamClass *class;
131
4.77k
  GInputStream *input_stream;
132
4.77k
  GFileInfo *info;
133
  
134
4.77k
  g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
135
  
136
4.77k
  input_stream = G_INPUT_STREAM (stream);
137
  
138
4.77k
  if (!g_input_stream_set_pending (input_stream, error))
139
0
    return NULL;
140
      
141
4.77k
  info = NULL;
142
  
143
4.77k
  if (cancellable)
144
0
    g_cancellable_push_current (cancellable);
145
  
146
4.77k
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
147
4.77k
  if (class->query_info)
148
4.77k
    info = class->query_info (stream, attributes, cancellable, error);
149
0
  else
150
0
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
151
0
                         _("Stream doesn’t support query_info"));
152
153
4.77k
  if (cancellable)
154
0
    g_cancellable_pop_current (cancellable);
155
  
156
4.77k
  g_input_stream_clear_pending (input_stream);
157
  
158
4.77k
  return info;
159
4.77k
}
160
161
static void
162
async_ready_callback_wrapper (GObject      *source_object,
163
                              GAsyncResult *res,
164
                              gpointer      user_data)
165
0
{
166
0
  GFileInputStream *stream = G_FILE_INPUT_STREAM (source_object);
167
168
0
  g_input_stream_clear_pending (G_INPUT_STREAM (stream));
169
0
  if (stream->priv->outstanding_callback)
170
0
    (*stream->priv->outstanding_callback) (source_object, res, user_data);
171
0
  g_object_unref (stream);
172
0
}
173
174
/**
175
 * g_file_input_stream_query_info_async:
176
 * @stream: a #GFileInputStream.
177
 * @attributes: a file attribute query string.
178
 * @io_priority: the [I/O priority][io-priority] of the request
179
 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. 
180
 * @callback: (scope async): callback to call when the request is satisfied
181
 * @user_data: (closure): the data to pass to callback function
182
 * 
183
 * Queries the stream information asynchronously.
184
 * When the operation is finished @callback will be called. 
185
 * You can then call g_file_input_stream_query_info_finish() 
186
 * to get the result of the operation.
187
 *
188
 * For the synchronous version of this function, 
189
 * see g_file_input_stream_query_info(). 
190
 * 
191
 * If @cancellable is not %NULL, then the operation can be cancelled by
192
 * triggering the cancellable object from another thread. If the operation
193
 * was cancelled, the error %G_IO_ERROR_CANCELLED will be set
194
 *  
195
 **/
196
void
197
g_file_input_stream_query_info_async (GFileInputStream    *stream,
198
                                      const char          *attributes,
199
                                      int                  io_priority,
200
                                      GCancellable        *cancellable,
201
                                      GAsyncReadyCallback  callback,
202
                                      gpointer             user_data)
203
0
{
204
0
  GFileInputStreamClass *klass;
205
0
  GInputStream *input_stream;
206
0
  GError *error = NULL;
207
208
0
  g_return_if_fail (G_IS_FILE_INPUT_STREAM (stream));
209
210
0
  input_stream = G_INPUT_STREAM (stream);
211
  
212
0
  if (!g_input_stream_set_pending (input_stream, &error))
213
0
    {
214
0
      g_task_report_error (stream, callback, user_data,
215
0
                           g_file_input_stream_query_info_async,
216
0
                           error);
217
0
      return;
218
0
    }
219
220
0
  klass = G_FILE_INPUT_STREAM_GET_CLASS (stream);
221
222
0
  stream->priv->outstanding_callback = callback;
223
0
  g_object_ref (stream);
224
0
  klass->query_info_async (stream, attributes, io_priority, cancellable,
225
0
                           async_ready_callback_wrapper, user_data);
226
0
}
227
228
/**
229
 * g_file_input_stream_query_info_finish:
230
 * @stream: a #GFileInputStream.
231
 * @result: a #GAsyncResult.
232
 * @error: a #GError location to store the error occurring, 
233
 *     or %NULL to ignore.
234
 * 
235
 * Finishes an asynchronous info query operation.
236
 * 
237
 * Returns: (transfer full): #GFileInfo. 
238
 **/
239
GFileInfo *
240
g_file_input_stream_query_info_finish (GFileInputStream  *stream,
241
                                       GAsyncResult      *result,
242
                                       GError           **error)
243
0
{
244
0
  GFileInputStreamClass *class;
245
246
0
  g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
247
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
248
249
0
  if (g_async_result_legacy_propagate_error (result, error))
250
0
    return NULL;
251
0
  else if (g_async_result_is_tagged (result, g_file_input_stream_query_info_async))
252
0
    return g_task_propagate_pointer (G_TASK (result), error);
253
254
0
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
255
0
  return class->query_info_finish (stream, result, error);
256
0
}
257
258
static goffset
259
g_file_input_stream_tell (GFileInputStream *stream)
260
4.76k
{
261
4.76k
  GFileInputStreamClass *class;
262
4.76k
  goffset offset;
263
264
4.76k
  g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), 0);
265
266
4.76k
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
267
268
4.76k
  offset = 0;
269
4.76k
  if (class->tell)
270
4.76k
    offset = class->tell (stream);
271
272
4.76k
  return offset;
273
4.76k
}
274
275
static goffset
276
g_file_input_stream_seekable_tell (GSeekable *seekable)
277
4.76k
{
278
4.76k
  return g_file_input_stream_tell (G_FILE_INPUT_STREAM (seekable));
279
4.76k
}
280
281
static gboolean
282
g_file_input_stream_can_seek (GFileInputStream *stream)
283
0
{
284
0
  GFileInputStreamClass *class;
285
0
  gboolean can_seek;
286
287
0
  g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
288
289
0
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
290
291
0
  can_seek = FALSE;
292
0
  if (class->seek)
293
0
    {
294
0
      can_seek = TRUE;
295
0
      if (class->can_seek)
296
0
  can_seek = class->can_seek (stream);
297
0
    }
298
  
299
0
  return can_seek;
300
0
}
301
302
static gboolean
303
g_file_input_stream_seekable_can_seek (GSeekable *seekable)
304
0
{
305
0
  return g_file_input_stream_can_seek (G_FILE_INPUT_STREAM (seekable));
306
0
}
307
308
static gboolean
309
g_file_input_stream_seek (GFileInputStream  *stream,
310
        goffset            offset,
311
        GSeekType          type,
312
        GCancellable      *cancellable,
313
        GError           **error)
314
9.35k
{
315
9.35k
  GFileInputStreamClass *class;
316
9.35k
  GInputStream *input_stream;
317
9.35k
  gboolean res;
318
319
9.35k
  g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
320
321
9.35k
  input_stream = G_INPUT_STREAM (stream);
322
9.35k
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
323
324
9.35k
  if (!class->seek)
325
0
    {
326
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
327
0
                           _("Seek not supported on stream"));
328
0
      return FALSE;
329
0
    }
330
331
9.35k
  if (!g_input_stream_set_pending (input_stream, error))
332
0
    return FALSE;
333
  
334
9.35k
  if (cancellable)
335
0
    g_cancellable_push_current (cancellable);
336
  
337
9.35k
  res = class->seek (stream, offset, type, cancellable, error);
338
  
339
9.35k
  if (cancellable)
340
0
    g_cancellable_pop_current (cancellable);
341
342
9.35k
  g_input_stream_clear_pending (input_stream);
343
  
344
9.35k
  return res;
345
9.35k
}
346
347
static gboolean
348
g_file_input_stream_seekable_seek (GSeekable     *seekable,
349
           goffset        offset,
350
           GSeekType      type,
351
           GCancellable  *cancellable,
352
           GError       **error)
353
9.35k
{
354
9.35k
  return g_file_input_stream_seek (G_FILE_INPUT_STREAM (seekable),
355
9.35k
           offset, type, cancellable, error);
356
9.35k
}
357
358
static gboolean
359
g_file_input_stream_seekable_can_truncate (GSeekable *seekable)
360
0
{
361
0
  return FALSE;
362
0
}
363
364
static gboolean
365
g_file_input_stream_seekable_truncate (GSeekable     *seekable,
366
               goffset        offset,
367
               GCancellable  *cancellable,
368
               GError       **error)
369
0
{
370
0
  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
371
0
                       _("Truncate not allowed on input stream"));
372
0
  return FALSE;
373
0
}
374
375
/********************************************
376
 *   Default implementation of async ops    *
377
 ********************************************/
378
379
static void
380
query_info_async_thread (GTask        *task,
381
                         gpointer      source_object,
382
                         gpointer      task_data,
383
                         GCancellable *cancellable)
384
0
{
385
0
  GFileInputStream *stream = source_object;
386
0
  const char *attributes = task_data;
387
0
  GFileInputStreamClass *class;
388
0
  GError *error = NULL;
389
0
  GFileInfo *info = NULL;
390
391
0
  class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
392
0
  if (class->query_info)
393
0
    info = class->query_info (stream, attributes, cancellable, &error);
394
0
  else
395
0
    g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
396
0
                         _("Stream doesn’t support query_info"));
397
398
0
  if (info == NULL)
399
0
    g_task_return_error (task, error);
400
0
  else
401
0
    g_task_return_pointer (task, info, g_object_unref);
402
0
}
403
404
static void
405
g_file_input_stream_real_query_info_async (GFileInputStream    *stream,
406
                                           const char          *attributes,
407
                                           int                  io_priority,
408
                                           GCancellable        *cancellable,
409
                                           GAsyncReadyCallback  callback,
410
                                           gpointer             user_data)
411
0
{
412
0
  GTask *task;
413
414
0
  task = g_task_new (stream, cancellable, callback, user_data);
415
0
  g_task_set_source_tag (task, g_file_input_stream_real_query_info_async);
416
0
  g_task_set_task_data (task, g_strdup (attributes), g_free);
417
0
  g_task_set_priority (task, io_priority);
418
  
419
0
  g_task_run_in_thread (task, query_info_async_thread);
420
0
  g_object_unref (task);
421
0
}
422
423
static GFileInfo *
424
g_file_input_stream_real_query_info_finish (GFileInputStream  *stream,
425
                                            GAsyncResult      *res,
426
                                            GError           **error)
427
0
{
428
0
  g_return_val_if_fail (g_task_is_valid (res, stream), NULL);
429
430
0
  return g_task_propagate_pointer (G_TASK (res), error);
431
0
}