Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gresourcefile.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 <string.h>
24
25
#include "gresource.h"
26
#include "gresourcefile.h"
27
#include "gfileattribute.h"
28
#include <gfileattribute-priv.h>
29
#include <gfileinfo-priv.h>
30
#include "gfile.h"
31
#include "gfilemonitor.h"
32
#include "gseekable.h"
33
#include "gfileinputstream.h"
34
#include "gfileinfo.h"
35
#include "gfileenumerator.h"
36
#include "gcontenttype.h"
37
#include "gioerror.h"
38
#include <glib/gstdio.h>
39
#include "glibintl.h"
40
41
struct _GResourceFile
42
{
43
  GObject parent_instance;
44
45
  char *path;
46
};
47
48
struct _GResourceFileEnumerator
49
{
50
  GFileEnumerator parent;
51
52
  GFileAttributeMatcher *matcher;
53
  char *path;
54
  char *attributes;
55
  GFileQueryInfoFlags flags;
56
  int index;
57
58
  char **children;
59
};
60
61
struct _GResourceFileEnumeratorClass
62
{
63
  GFileEnumeratorClass parent_class;
64
};
65
66
typedef struct _GResourceFileEnumerator        GResourceFileEnumerator;
67
typedef struct _GResourceFileEnumeratorClass   GResourceFileEnumeratorClass;
68
69
static void g_resource_file_file_iface_init (GFileIface *iface);
70
71
static GFileAttributeInfoList *resource_writable_attributes = NULL;
72
static GFileAttributeInfoList *resource_writable_namespaces = NULL;
73
74
static GType _g_resource_file_enumerator_get_type (void);
75
76
0
#define G_TYPE_RESOURCE_FILE_ENUMERATOR         (_g_resource_file_enumerator_get_type ())
77
0
#define G_RESOURCE_FILE_ENUMERATOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumerator))
78
#define G_RESOURCE_FILE_ENUMERATOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
79
#define G_IS_RESOURCE_FILE_ENUMERATOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR))
80
#define G_IS_RESOURCE_FILE_ENUMERATOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_ENUMERATOR))
81
#define G_RESOURCE_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
82
83
0
#define G_TYPE_RESOURCE_FILE_INPUT_STREAM         (_g_resource_file_input_stream_get_type ())
84
0
#define G_RESOURCE_FILE_INPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStream))
85
#define G_RESOURCE_FILE_INPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
86
#define G_IS_RESOURCE_FILE_INPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
87
#define G_IS_RESOURCE_FILE_INPUT_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
88
#define G_RESOURCE_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
89
90
typedef struct _GResourceFileInputStream         GResourceFileInputStream;
91
typedef struct _GResourceFileInputStreamClass    GResourceFileInputStreamClass;
92
93
#define g_resource_file_get_type _g_resource_file_get_type
94
G_DEFINE_TYPE_WITH_CODE (GResourceFile, g_resource_file, G_TYPE_OBJECT,
95
       G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
96
            g_resource_file_file_iface_init))
97
98
#define g_resource_file_enumerator_get_type _g_resource_file_enumerator_get_type
99
G_DEFINE_TYPE (GResourceFileEnumerator, g_resource_file_enumerator, G_TYPE_FILE_ENUMERATOR)
100
101
static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
102
               const char           *attributes,
103
               GFileQueryInfoFlags   flags,
104
               GCancellable         *cancellable,
105
               GError              **error);
106
107
108
static GType              _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
109
110
static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
111
112
113
static void
114
g_resource_file_finalize (GObject *object)
115
0
{
116
0
  GResourceFile *resource;
117
118
0
  resource = G_RESOURCE_FILE (object);
119
120
0
  g_free (resource->path);
121
122
0
  G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
123
0
}
124
125
static void
126
g_resource_file_class_init (GResourceFileClass *klass)
127
0
{
128
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129
130
0
  gobject_class->finalize = g_resource_file_finalize;
131
132
0
  resource_writable_attributes = g_file_attribute_info_list_new ();
133
0
  resource_writable_namespaces = g_file_attribute_info_list_new ();
134
0
}
135
136
static void
137
g_resource_file_init (GResourceFile *resource)
138
0
{
139
0
}
140
141
static inline gchar *
142
scan_backwards (const gchar *begin,
143
                const gchar *end,
144
                gchar        c)
145
0
{
146
0
  while (end >= begin)
147
0
    {
148
0
      if (*end == c)
149
0
        return (gchar *)end;
150
0
      end--;
151
0
    }
152
153
0
  return NULL;
154
0
}
155
156
static inline void
157
pop_to_previous_part (const gchar  *begin,
158
                      gchar       **out)
159
0
{
160
0
  if (*out > begin)
161
0
    *out = scan_backwards (begin, *out - 1, '/');
162
0
}
163
164
/*
165
 * canonicalize_filename:
166
 * @in: the path to be canonicalized
167
 *
168
 * The path @in may contain non-canonical path pieces such as "../"
169
 * or duplicated "/". This will resolve those into a form that only
170
 * contains a single / at a time and resolves all "../". The resulting
171
 * path must also start with a /.
172
 *
173
 * Returns: the canonical form of the path
174
 */
175
static char *
176
canonicalize_filename (const char *in)
177
0
{
178
0
  gchar *bptr;
179
0
  char *out;
180
181
0
  bptr = out = g_malloc (strlen (in) + 2);
182
0
  *out = '/';
183
184
0
  while (*in != 0)
185
0
    {
186
0
      g_assert (*out == '/');
187
188
      /* move past slashes */
189
0
      while (*in == '/')
190
0
        in++;
191
192
      /* Handle ./ ../ .\0 ..\0 */
193
0
      if (*in == '.')
194
0
        {
195
          /* If this is ../ or ..\0 move up */
196
0
          if (in[1] == '.' && (in[2] == '/' || in[2] == 0))
197
0
            {
198
0
              pop_to_previous_part (bptr, &out);
199
0
              in += 2;
200
0
              continue;
201
0
            }
202
203
          /* If this is ./ skip past it */
204
0
          if (in[1] == '/' || in[1] == 0)
205
0
            {
206
0
              in += 1;
207
0
              continue;
208
0
            }
209
0
        }
210
211
      /* Scan to the next path piece */
212
0
      while (*in != 0 && *in != '/')
213
0
        *(++out) = *(in++);
214
215
      /* Add trailing /, compress the rest on the next go round. */
216
0
      if (*in == '/')
217
0
        *(++out) = *(in++);
218
0
    }
219
220
  /* Trim trailing / from path */
221
0
  if (out > bptr && *out == '/')
222
0
    *out = 0;
223
0
  else
224
0
    *(++out) = 0;
225
226
0
  return bptr;
227
0
}
228
229
static GFile *
230
g_resource_file_new_for_path (const char *path)
231
0
{
232
0
  GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
233
234
0
  resource->path = canonicalize_filename (path);
235
236
0
  return G_FILE (resource);
237
0
}
238
239
GFile *
240
_g_resource_file_new (const char *uri)
241
0
{
242
0
  GFile *resource;
243
0
  char *path;
244
245
0
  path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
246
0
  resource = g_resource_file_new_for_path (path);
247
0
  g_free (path);
248
249
0
  return G_FILE (resource);
250
0
}
251
252
static gboolean
253
g_resource_file_is_native (GFile *file)
254
0
{
255
0
  return FALSE;
256
0
}
257
258
static gboolean
259
g_resource_file_has_uri_scheme (GFile      *file,
260
        const char *uri_scheme)
261
0
{
262
0
  return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
263
0
}
264
265
static char *
266
g_resource_file_get_uri_scheme (GFile *file)
267
0
{
268
0
  return g_strdup ("resource");
269
0
}
270
271
static char *
272
g_resource_file_get_basename (GFile *file)
273
0
{
274
0
  gchar *base;
275
276
0
  base = strrchr (G_RESOURCE_FILE (file)->path, '/');
277
0
  return g_strdup (base + 1);
278
0
}
279
280
static char *
281
g_resource_file_get_path (GFile *file)
282
0
{
283
0
  return NULL;
284
0
}
285
286
static char *
287
g_resource_file_get_uri (GFile *file)
288
0
{
289
0
  char *escaped, *res;
290
0
  escaped = g_uri_escape_string (G_RESOURCE_FILE (file)->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
291
0
  res = g_strconcat ("resource://", escaped, NULL);
292
0
  g_free (escaped);
293
0
  return res;
294
0
}
295
296
static char *
297
g_resource_file_get_parse_name (GFile *file)
298
0
{
299
0
  return g_resource_file_get_uri (file);
300
0
}
301
302
static GFile *
303
g_resource_file_get_parent (GFile *file)
304
0
{
305
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
306
0
  GResourceFile *parent;
307
0
  gchar *end;
308
309
0
  end = strrchr (resource->path, '/');
310
311
0
  if (end == G_RESOURCE_FILE (file)->path)
312
0
    return NULL;
313
314
0
  parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
315
0
  parent->path = g_strndup (resource->path,
316
0
          end - resource->path);
317
318
0
  return G_FILE (parent);
319
0
}
320
321
static GFile *
322
g_resource_file_dup (GFile *file)
323
0
{
324
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
325
326
0
  return g_resource_file_new_for_path (resource->path);
327
0
}
328
329
static guint
330
g_resource_file_hash (GFile *file)
331
0
{
332
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
333
334
0
  return g_str_hash (resource->path);
335
0
}
336
337
static gboolean
338
g_resource_file_equal (GFile *file1,
339
           GFile *file2)
340
0
{
341
0
  GResourceFile *resource1 = G_RESOURCE_FILE (file1);
342
0
  GResourceFile *resource2 = G_RESOURCE_FILE (file2);
343
344
0
  return g_str_equal (resource1->path, resource2->path);
345
0
}
346
347
static const char *
348
match_prefix (const char *path,
349
        const char *prefix)
350
0
{
351
0
  int prefix_len;
352
353
0
  prefix_len = strlen (prefix);
354
0
  if (strncmp (path, prefix, prefix_len) != 0)
355
0
    return NULL;
356
357
  /* Handle the case where prefix is the root, so that
358
   * the IS_DIR_SEPRARATOR check below works */
359
0
  if (prefix_len > 0 &&
360
0
      prefix[prefix_len-1] == '/')
361
0
    prefix_len--;
362
363
0
  return path + prefix_len;
364
0
}
365
366
static gboolean
367
g_resource_file_prefix_matches (GFile *parent,
368
        GFile *descendant)
369
0
{
370
0
  GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
371
0
  GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
372
0
  const char *remainder;
373
374
0
  remainder = match_prefix (descendant_resource->path, parent_resource->path);
375
0
  if (remainder != NULL && *remainder == '/')
376
0
    return TRUE;
377
0
  return FALSE;
378
0
}
379
380
static char *
381
g_resource_file_get_relative_path (GFile *parent,
382
           GFile *descendant)
383
0
{
384
0
  GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
385
0
  GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
386
0
  const char *remainder;
387
388
0
  remainder = match_prefix (descendant_resource->path, parent_resource->path);
389
390
0
  if (remainder != NULL && *remainder == '/')
391
0
    return g_strdup (remainder + 1);
392
0
  return NULL;
393
0
}
394
395
static GFile *
396
g_resource_file_resolve_relative_path (GFile      *file,
397
               const char *relative_path)
398
0
{
399
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
400
0
  char *filename;
401
0
  GFile *child;
402
403
0
  if (relative_path[0] == '/')
404
0
    return g_resource_file_new_for_path (relative_path);
405
406
0
  filename = g_build_path ("/", resource->path, relative_path, NULL);
407
0
  child = g_resource_file_new_for_path (filename);
408
0
  g_free (filename);
409
410
0
  return child;
411
0
}
412
413
static GFileEnumerator *
414
g_resource_file_enumerate_children (GFile                *file,
415
            const char           *attributes,
416
            GFileQueryInfoFlags   flags,
417
            GCancellable         *cancellable,
418
            GError              **error)
419
0
{
420
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
421
0
  return _g_resource_file_enumerator_new (resource,
422
0
            attributes, flags,
423
0
            cancellable, error);
424
0
}
425
426
static GFile *
427
g_resource_file_get_child_for_display_name (GFile        *file,
428
              const char   *display_name,
429
              GError      **error)
430
0
{
431
0
  GFile *new_file;
432
433
0
  new_file = g_file_get_child (file, display_name);
434
435
0
  return new_file;
436
0
}
437
438
static GFileInfo *
439
g_resource_file_query_info (GFile                *file,
440
          const char           *attributes,
441
          GFileQueryInfoFlags   flags,
442
          GCancellable         *cancellable,
443
          GError              **error)
444
0
{
445
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
446
0
  GError *my_error = NULL;
447
0
  GFileInfo *info;
448
0
  GFileAttributeMatcher *matcher;
449
0
  gboolean res;
450
0
  gsize size;
451
0
  guint32 resource_flags;
452
0
  char **children;
453
0
  gboolean is_dir;
454
0
  char *base;
455
456
0
  is_dir = FALSE;
457
0
  children = g_resources_enumerate_children (resource->path, 0, NULL);
458
0
  if (children != NULL)
459
0
    {
460
0
      g_strfreev (children);
461
0
      is_dir = TRUE;
462
0
    }
463
464
  /* root is always there */
465
0
  if (strcmp ("/", resource->path) == 0)
466
0
    is_dir = TRUE;
467
468
0
  if (!is_dir)
469
0
    {
470
0
      res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
471
0
      if (!res)
472
0
  {
473
0
    if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
474
0
      {
475
0
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
476
0
         _("The resource at “%s” does not exist"),
477
0
         resource->path);
478
0
      }
479
0
    else
480
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
481
0
                                 my_error->message);
482
0
    g_clear_error (&my_error);
483
0
    return FALSE;
484
0
  }
485
0
    }
486
487
0
  matcher = g_file_attribute_matcher_new (attributes);
488
489
0
  info = g_file_info_new ();
490
0
  base = g_resource_file_get_basename (file);
491
0
  g_file_info_set_name (info, base);
492
0
  g_file_info_set_display_name (info, base);
493
494
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, TRUE);
495
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, FALSE);
496
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, FALSE);
497
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, FALSE);
498
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, FALSE);
499
0
  _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, FALSE);
500
501
0
  if (is_dir)
502
0
    {
503
0
      g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
504
0
    }
505
0
  else
506
0
    {
507
0
      GBytes *bytes;
508
0
      char *content_type;
509
510
0
      g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
511
0
      g_file_info_set_size (info, size);
512
513
0
      if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
514
0
           ((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) && 
515
0
            _g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) &&
516
0
          (bytes = g_resources_lookup_data (resource->path, 0, NULL)))
517
0
        {
518
0
          const guchar *data;
519
0
          gsize data_size;
520
521
0
          data = g_bytes_get_data (bytes, &data_size);
522
0
          content_type = g_content_type_guess (base, data, data_size, NULL);
523
524
0
          g_bytes_unref (bytes);
525
0
        }
526
0
      else
527
0
        content_type = NULL;
528
529
0
      if (content_type)
530
0
        {
531
0
          _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE, content_type);
532
0
          _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
533
534
0
          g_free (content_type);
535
0
        }
536
0
    }
537
538
0
  g_free (base);
539
0
  g_file_attribute_matcher_unref (matcher);
540
541
0
  return info;
542
0
}
543
544
static GFileInfo *
545
g_resource_file_query_filesystem_info (GFile         *file,
546
                                       const char    *attributes,
547
                                       GCancellable  *cancellable,
548
                                       GError       **error)
549
0
{
550
0
  GFileInfo *info;
551
0
  GFileAttributeMatcher *matcher;
552
553
0
  info = g_file_info_new ();
554
555
0
  matcher = g_file_attribute_matcher_new (attributes);
556
0
  if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
557
0
    g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "resource");
558
559
0
  if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))    g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
560
561
0
  g_file_attribute_matcher_unref (matcher);
562
563
0
  return info;
564
0
}
565
566
static GFileAttributeInfoList *
567
g_resource_file_query_settable_attributes (GFile         *file,
568
             GCancellable  *cancellable,
569
             GError       **error)
570
0
{
571
0
  return g_file_attribute_info_list_ref (resource_writable_attributes);
572
0
}
573
574
static GFileAttributeInfoList *
575
g_resource_file_query_writable_namespaces (GFile         *file,
576
             GCancellable  *cancellable,
577
             GError       **error)
578
0
{
579
0
  return g_file_attribute_info_list_ref (resource_writable_namespaces);
580
0
}
581
582
static GFileInputStream *
583
g_resource_file_read (GFile         *file,
584
          GCancellable  *cancellable,
585
          GError       **error)
586
0
{
587
0
  GResourceFile *resource = G_RESOURCE_FILE (file);
588
0
  GError *my_error = NULL;
589
0
  GInputStream *stream;
590
0
  GFileInputStream *res;
591
592
0
  stream = g_resources_open_stream (resource->path, 0, &my_error);
593
594
0
  if (stream == NULL)
595
0
    {
596
0
      if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
597
0
  {
598
0
    g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
599
0
           _("The resource at “%s” does not exist"),
600
0
           resource->path);
601
0
  }
602
0
      else
603
0
  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
604
0
                             my_error->message);
605
0
      g_clear_error (&my_error);
606
0
      return NULL;
607
0
    }
608
609
0
  res = _g_resource_file_input_stream_new (stream, file);
610
0
  g_object_unref (stream);
611
0
  return res;
612
0
}
613
614
typedef GFileMonitor GResourceFileMonitor;
615
typedef GFileMonitorClass GResourceFileMonitorClass;
616
617
GType g_resource_file_monitor_get_type (void);
618
619
G_DEFINE_TYPE (GResourceFileMonitor, g_resource_file_monitor, G_TYPE_FILE_MONITOR)
620
621
static gboolean
622
g_resource_file_monitor_cancel (GFileMonitor *monitor)
623
0
{
624
0
  return TRUE;
625
0
}
626
627
static void
628
g_resource_file_monitor_init (GResourceFileMonitor *monitor)
629
0
{
630
0
}
631
632
static void
633
g_resource_file_monitor_class_init (GResourceFileMonitorClass *class)
634
0
{
635
0
  class->cancel = g_resource_file_monitor_cancel;
636
0
}
637
638
static GFileMonitor *
639
g_resource_file_monitor_file (GFile              *file,
640
                              GFileMonitorFlags   flags,
641
                              GCancellable       *cancellable,
642
                              GError            **error)
643
0
{
644
0
  return g_object_new (g_resource_file_monitor_get_type (), NULL);
645
0
}
646
647
static void
648
g_resource_file_file_iface_init (GFileIface *iface)
649
0
{
650
0
  iface->dup = g_resource_file_dup;
651
0
  iface->hash = g_resource_file_hash;
652
0
  iface->equal = g_resource_file_equal;
653
0
  iface->is_native = g_resource_file_is_native;
654
0
  iface->has_uri_scheme = g_resource_file_has_uri_scheme;
655
0
  iface->get_uri_scheme = g_resource_file_get_uri_scheme;
656
0
  iface->get_basename = g_resource_file_get_basename;
657
0
  iface->get_path = g_resource_file_get_path;
658
0
  iface->get_uri = g_resource_file_get_uri;
659
0
  iface->get_parse_name = g_resource_file_get_parse_name;
660
0
  iface->get_parent = g_resource_file_get_parent;
661
0
  iface->prefix_matches = g_resource_file_prefix_matches;
662
0
  iface->get_relative_path = g_resource_file_get_relative_path;
663
0
  iface->resolve_relative_path = g_resource_file_resolve_relative_path;
664
0
  iface->get_child_for_display_name = g_resource_file_get_child_for_display_name;
665
0
  iface->enumerate_children = g_resource_file_enumerate_children;
666
0
  iface->query_info = g_resource_file_query_info;
667
0
  iface->query_filesystem_info = g_resource_file_query_filesystem_info;
668
0
  iface->query_settable_attributes = g_resource_file_query_settable_attributes;
669
0
  iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
670
0
  iface->read_fn = g_resource_file_read;
671
0
  iface->monitor_file = g_resource_file_monitor_file;
672
673
0
  iface->supports_thread_contexts = TRUE;
674
0
}
675
676
static GFileInfo *g_resource_file_enumerator_next_file (GFileEnumerator  *enumerator,
677
              GCancellable     *cancellable,
678
              GError          **error);
679
static gboolean   g_resource_file_enumerator_close     (GFileEnumerator  *enumerator,
680
              GCancellable     *cancellable,
681
              GError          **error);
682
683
static void
684
g_resource_file_enumerator_finalize (GObject *object)
685
0
{
686
0
  GResourceFileEnumerator *resource;
687
688
0
  resource = G_RESOURCE_FILE_ENUMERATOR (object);
689
690
0
  g_strfreev (resource->children);
691
0
  g_free (resource->path);
692
0
  g_free (resource->attributes);
693
694
0
  G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
695
0
}
696
697
static void
698
g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
699
0
{
700
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
701
0
  GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
702
703
0
  gobject_class->finalize = g_resource_file_enumerator_finalize;
704
705
0
  enumerator_class->next_file = g_resource_file_enumerator_next_file;
706
0
  enumerator_class->close_fn = g_resource_file_enumerator_close;
707
0
}
708
709
static void
710
g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
711
0
{
712
0
}
713
714
static GFileEnumerator *
715
_g_resource_file_enumerator_new (GResourceFile *file,
716
         const char           *attributes,
717
         GFileQueryInfoFlags   flags,
718
         GCancellable         *cancellable,
719
         GError              **error)
720
0
{
721
0
  GResourceFileEnumerator *resource;
722
0
  char **children;
723
0
  gboolean res;
724
725
0
  children = g_resources_enumerate_children (file->path, 0, NULL);
726
0
  if (children == NULL &&
727
0
      strcmp ("/", file->path) != 0)
728
0
    {
729
0
      res = g_resources_get_info (file->path, 0, NULL, NULL, NULL);
730
0
      if (res)
731
0
  g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
732
0
         _("The resource at “%s” is not a directory"),
733
0
         file->path);
734
0
      else
735
0
  g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
736
0
         _("The resource at “%s” does not exist"),
737
0
         file->path);
738
0
      return NULL;
739
0
    }
740
741
0
  resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
742
0
         "container", file,
743
0
         NULL);
744
745
0
  resource->children = children;
746
0
  resource->path = g_strdup (file->path);
747
0
  resource->attributes = g_strdup (attributes);
748
0
  resource->flags = flags;
749
750
0
  return G_FILE_ENUMERATOR (resource);
751
0
}
752
753
static GFileInfo *
754
g_resource_file_enumerator_next_file (GFileEnumerator  *enumerator,
755
              GCancellable     *cancellable,
756
              GError          **error)
757
0
{
758
0
  GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
759
0
  char *path;
760
0
  GFileInfo *info;
761
0
  GFile *file;
762
763
0
  if (resource->children == NULL ||
764
0
      resource->children[resource->index] == NULL)
765
0
    return NULL;
766
767
0
  path = g_build_path ("/", resource->path, resource->children[resource->index++], NULL);
768
0
  file = g_resource_file_new_for_path (path);
769
0
  g_free (path);
770
771
0
  info = g_file_query_info (file,
772
0
          resource->attributes,
773
0
          resource->flags,
774
0
          cancellable,
775
0
          error);
776
777
0
  g_object_unref (file);
778
779
0
  return info;
780
0
}
781
782
static gboolean
783
g_resource_file_enumerator_close (GFileEnumerator  *enumerator,
784
             GCancellable     *cancellable,
785
             GError          **error)
786
0
{
787
0
  return TRUE;
788
0
}
789
790
791
struct _GResourceFileInputStream
792
{
793
  GFileInputStream parent_instance;
794
  GInputStream *stream;
795
  GFile *file;
796
};
797
798
struct _GResourceFileInputStreamClass
799
{
800
  GFileInputStreamClass parent_class;
801
};
802
803
#define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
804
G_DEFINE_TYPE (GResourceFileInputStream, g_resource_file_input_stream, G_TYPE_FILE_INPUT_STREAM)
805
806
static gssize     g_resource_file_input_stream_read       (GInputStream      *stream,
807
                 void              *buffer,
808
                 gsize              count,
809
                 GCancellable      *cancellable,
810
                 GError           **error);
811
static gssize     g_resource_file_input_stream_skip       (GInputStream      *stream,
812
                 gsize              count,
813
                 GCancellable      *cancellable,
814
                 GError           **error);
815
static gboolean   g_resource_file_input_stream_close      (GInputStream      *stream,
816
                 GCancellable      *cancellable,
817
                 GError           **error);
818
static goffset    g_resource_file_input_stream_tell       (GFileInputStream  *stream);
819
static gboolean   g_resource_file_input_stream_can_seek   (GFileInputStream  *stream);
820
static gboolean   g_resource_file_input_stream_seek       (GFileInputStream  *stream,
821
                 goffset            offset,
822
                 GSeekType          type,
823
                 GCancellable      *cancellable,
824
                 GError           **error);
825
static GFileInfo *g_resource_file_input_stream_query_info (GFileInputStream  *stream,
826
                 const char        *attributes,
827
                 GCancellable      *cancellable,
828
                 GError           **error);
829
830
static void
831
g_resource_file_input_stream_finalize (GObject *object)
832
0
{
833
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
834
835
0
  g_object_unref (file->stream);
836
0
  g_object_unref (file->file);
837
0
  G_OBJECT_CLASS (g_resource_file_input_stream_parent_class)->finalize (object);
838
0
}
839
840
static void
841
g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
842
0
{
843
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
844
0
  GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
845
0
  GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
846
847
0
  gobject_class->finalize = g_resource_file_input_stream_finalize;
848
849
0
  stream_class->read_fn = g_resource_file_input_stream_read;
850
0
  stream_class->skip = g_resource_file_input_stream_skip;
851
0
  stream_class->close_fn = g_resource_file_input_stream_close;
852
0
  file_stream_class->tell = g_resource_file_input_stream_tell;
853
0
  file_stream_class->can_seek = g_resource_file_input_stream_can_seek;
854
0
  file_stream_class->seek = g_resource_file_input_stream_seek;
855
0
  file_stream_class->query_info = g_resource_file_input_stream_query_info;
856
0
}
857
858
static void
859
g_resource_file_input_stream_init (GResourceFileInputStream *info)
860
0
{
861
0
}
862
863
static GFileInputStream *
864
_g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
865
0
{
866
0
  GResourceFileInputStream *stream;
867
868
0
  stream = g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM, NULL);
869
0
  stream->stream = g_object_ref (in_stream);
870
0
  stream->file = g_object_ref (file);
871
872
0
  return G_FILE_INPUT_STREAM (stream);
873
0
}
874
875
static gssize
876
g_resource_file_input_stream_read (GInputStream  *stream,
877
           void          *buffer,
878
           gsize          count,
879
           GCancellable  *cancellable,
880
           GError       **error)
881
0
{
882
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
883
0
  return g_input_stream_read (file->stream,
884
0
            buffer, count, cancellable, error);
885
0
}
886
887
static gssize
888
g_resource_file_input_stream_skip (GInputStream  *stream,
889
           gsize          count,
890
           GCancellable  *cancellable,
891
           GError       **error)
892
0
{
893
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
894
0
  return g_input_stream_skip (file->stream,
895
0
            count, cancellable, error);
896
0
}
897
898
static gboolean
899
g_resource_file_input_stream_close (GInputStream  *stream,
900
            GCancellable  *cancellable,
901
            GError       **error)
902
0
{
903
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
904
0
  return g_input_stream_close (file->stream,
905
0
             cancellable, error);
906
0
}
907
908
909
static goffset
910
g_resource_file_input_stream_tell (GFileInputStream *stream)
911
0
{
912
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
913
914
0
  if (!G_IS_SEEKABLE (file->stream))
915
0
      return 0;
916
917
0
  return g_seekable_tell (G_SEEKABLE (file->stream));
918
0
}
919
920
static gboolean
921
g_resource_file_input_stream_can_seek (GFileInputStream *stream)
922
0
{
923
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
924
925
0
  return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
926
0
}
927
928
static gboolean
929
g_resource_file_input_stream_seek (GFileInputStream  *stream,
930
           goffset            offset,
931
           GSeekType          type,
932
           GCancellable      *cancellable,
933
           GError           **error)
934
0
{
935
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
936
937
0
  if (!G_IS_SEEKABLE (file->stream))
938
0
    {
939
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
940
0
         _("Input stream doesn’t implement seek"));
941
0
      return FALSE;
942
0
    }
943
944
0
  return g_seekable_seek (G_SEEKABLE (file->stream),
945
0
        offset, type, cancellable, error);
946
0
}
947
948
static GFileInfo *
949
g_resource_file_input_stream_query_info (GFileInputStream  *stream,
950
           const char        *attributes,
951
           GCancellable      *cancellable,
952
           GError           **error)
953
0
{
954
0
  GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
955
956
0
  return g_file_query_info (file->file, attributes, 0, cancellable, error);
957
0
}