Coverage Report

Created: 2025-07-17 06:56

/src/rauc/subprojects/glib-2.76.5/glib/giounix.c
Line
Count
Source (jump to first uncovered line)
1
/* GLIB - Library of useful routines for C programming
2
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3
 *
4
 * giounix.c: IO Channels using unix file descriptors
5
 * Copyright 1998 Owen Taylor
6
 *
7
 * SPDX-License-Identifier: LGPL-2.1-or-later
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/*
24
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25
 * file for a list of people on the GLib Team.  See the ChangeLog
26
 * files for a list of changes.  These files are distributed with
27
 * GLib at ftp://ftp.gtk.org/pub/gtk/.
28
 */
29
30
/*
31
 * MT safe
32
 */
33
34
#include "config.h"
35
36
#define _POSIX_SOURCE   /* for SSIZE_MAX */
37
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
#include <stdio.h>
41
#include <unistd.h>
42
#include <errno.h>
43
#include <string.h>
44
#include <fcntl.h>
45
#include <glib/gstdio.h>
46
47
#ifndef O_CLOEXEC
48
#define O_CLOEXEC 0
49
#endif
50
51
#include "giochannel.h"
52
53
#include "gerror.h"
54
#include "gfileutils.h"
55
#include "gstrfuncs.h"
56
#include "gtestutils.h"
57
58
/*
59
 * Unix IO Channels
60
 */
61
62
typedef struct _GIOUnixChannel GIOUnixChannel;
63
typedef struct _GIOUnixWatch GIOUnixWatch;
64
65
struct _GIOUnixChannel
66
{
67
  GIOChannel channel;
68
  gint fd;
69
};
70
71
struct _GIOUnixWatch
72
{
73
  GSource       source;
74
  GPollFD       pollfd;
75
  GIOChannel   *channel;
76
  GIOCondition  condition;
77
};
78
79
80
static GIOStatus  g_io_unix_read    (GIOChannel   *channel,
81
             gchar        *buf,
82
             gsize         count,
83
             gsize        *bytes_read,
84
             GError      **err);
85
static GIOStatus  g_io_unix_write   (GIOChannel   *channel,
86
             const gchar  *buf,
87
             gsize         count,
88
             gsize        *bytes_written,
89
             GError      **err);
90
static GIOStatus  g_io_unix_seek    (GIOChannel   *channel,
91
             gint64        offset,
92
             GSeekType     type,
93
             GError      **err);
94
static GIOStatus  g_io_unix_close   (GIOChannel   *channel,
95
             GError      **err);
96
static void   g_io_unix_free    (GIOChannel   *channel);
97
static GSource*   g_io_unix_create_watch  (GIOChannel   *channel,
98
             GIOCondition  condition);
99
static GIOStatus  g_io_unix_set_flags (GIOChannel   *channel,
100
                               GIOFlags      flags,
101
             GError      **err);
102
static GIOFlags   g_io_unix_get_flags (GIOChannel   *channel);
103
104
static gboolean g_io_unix_prepare  (GSource     *source,
105
            gint        *timeout);
106
static gboolean g_io_unix_check    (GSource     *source);
107
static gboolean g_io_unix_dispatch (GSource     *source,
108
            GSourceFunc  callback,
109
            gpointer     user_data);
110
static void     g_io_unix_finalize (GSource     *source);
111
112
GSourceFuncs g_io_watch_funcs = {
113
  g_io_unix_prepare,
114
  g_io_unix_check,
115
  g_io_unix_dispatch,
116
  g_io_unix_finalize,
117
  NULL, NULL
118
};
119
120
static GIOFuncs unix_channel_funcs = {
121
  g_io_unix_read,
122
  g_io_unix_write,
123
  g_io_unix_seek,
124
  g_io_unix_close,
125
  g_io_unix_create_watch,
126
  g_io_unix_free,
127
  g_io_unix_set_flags,
128
  g_io_unix_get_flags,
129
};
130
131
static gboolean 
132
g_io_unix_prepare (GSource  *source,
133
       gint     *timeout)
134
0
{
135
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
136
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
137
138
0
  *timeout = -1;
139
140
  /* Only return TRUE here if _all_ bits in watch->condition will be set
141
   */
142
0
  return ((watch->condition & buffer_condition) == watch->condition);
143
0
}
144
145
static gboolean 
146
g_io_unix_check (GSource  *source)
147
0
{
148
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
149
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
150
0
  GIOCondition poll_condition = watch->pollfd.revents;
151
152
0
  return ((poll_condition | buffer_condition) & watch->condition);
153
0
}
154
155
static gboolean
156
g_io_unix_dispatch (GSource     *source,
157
        GSourceFunc  callback,
158
        gpointer     user_data)
159
160
0
{
161
0
  GIOFunc func = (GIOFunc)callback;
162
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
163
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
164
165
0
  if (!func)
166
0
    {
167
0
      g_warning ("IO watch dispatched without callback. "
168
0
     "You must call g_source_connect().");
169
0
      return FALSE;
170
0
    }
171
  
172
0
  return (*func) (watch->channel,
173
0
      (watch->pollfd.revents | buffer_condition) & watch->condition,
174
0
      user_data);
175
0
}
176
177
static void 
178
g_io_unix_finalize (GSource *source)
179
0
{
180
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
181
182
0
  g_io_channel_unref (watch->channel);
183
0
}
184
185
static GIOStatus
186
g_io_unix_read (GIOChannel *channel, 
187
    gchar      *buf, 
188
    gsize       count,
189
    gsize      *bytes_read,
190
    GError    **err)
191
0
{
192
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
193
0
  gssize result;
194
195
0
  if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
196
0
    count = SSIZE_MAX;
197
198
0
 retry:
199
0
  result = read (unix_channel->fd, buf, count);
200
201
0
  if (result < 0)
202
0
    {
203
0
      int errsv = errno;
204
0
      *bytes_read = 0;
205
206
0
      switch (errsv)
207
0
        {
208
0
#ifdef EINTR
209
0
          case EINTR:
210
0
            goto retry;
211
0
#endif
212
0
#ifdef EAGAIN
213
0
          case EAGAIN:
214
0
            return G_IO_STATUS_AGAIN;
215
0
#endif
216
0
          default:
217
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
218
0
                                 g_io_channel_error_from_errno (errsv),
219
0
                                 g_strerror (errsv));
220
0
            return G_IO_STATUS_ERROR;
221
0
        }
222
0
    }
223
224
0
  *bytes_read = result;
225
226
0
  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
227
0
}
228
229
static GIOStatus
230
g_io_unix_write (GIOChannel  *channel, 
231
     const gchar *buf, 
232
     gsize       count,
233
     gsize      *bytes_written,
234
     GError    **err)
235
0
{
236
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
237
0
  gssize result;
238
239
0
 retry:
240
0
  result = write (unix_channel->fd, buf, count);
241
242
0
  if (result < 0)
243
0
    {
244
0
      int errsv = errno;
245
0
      *bytes_written = 0;
246
247
0
      switch (errsv)
248
0
        {
249
0
#ifdef EINTR
250
0
          case EINTR:
251
0
            goto retry;
252
0
#endif
253
0
#ifdef EAGAIN
254
0
          case EAGAIN:
255
0
            return G_IO_STATUS_AGAIN;
256
0
#endif
257
0
          default:
258
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
259
0
                                 g_io_channel_error_from_errno (errsv),
260
0
                                 g_strerror (errsv));
261
0
            return G_IO_STATUS_ERROR;
262
0
        }
263
0
    }
264
265
0
  *bytes_written = result;
266
267
0
  return G_IO_STATUS_NORMAL;
268
0
}
269
270
static GIOStatus
271
g_io_unix_seek (GIOChannel *channel,
272
    gint64      offset, 
273
    GSeekType   type,
274
                GError    **err)
275
0
{
276
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
277
0
  int whence;
278
0
  off_t tmp_offset;
279
0
  off_t result;
280
281
0
  switch (type)
282
0
    {
283
0
    case G_SEEK_SET:
284
0
      whence = SEEK_SET;
285
0
      break;
286
0
    case G_SEEK_CUR:
287
0
      whence = SEEK_CUR;
288
0
      break;
289
0
    case G_SEEK_END:
290
0
      whence = SEEK_END;
291
0
      break;
292
0
    default:
293
0
      whence = -1; /* Shut the compiler up */
294
0
      g_assert_not_reached ();
295
0
    }
296
297
0
  tmp_offset = offset;
298
0
  if (tmp_offset != offset)
299
0
    {
300
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
301
0
                           g_io_channel_error_from_errno (EINVAL),
302
0
                           g_strerror (EINVAL));
303
0
      return G_IO_STATUS_ERROR;
304
0
    }
305
  
306
0
  result = lseek (unix_channel->fd, tmp_offset, whence);
307
308
0
  if (result < 0)
309
0
    {
310
0
      int errsv = errno;
311
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
312
0
                           g_io_channel_error_from_errno (errsv),
313
0
                           g_strerror (errsv));
314
0
      return G_IO_STATUS_ERROR;
315
0
    }
316
317
0
  return G_IO_STATUS_NORMAL;
318
0
}
319
320
321
static GIOStatus
322
g_io_unix_close (GIOChannel *channel,
323
     GError    **err)
324
0
{
325
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
326
327
0
  if (close (unix_channel->fd) < 0)
328
0
    {
329
0
      int errsv = errno;
330
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
331
0
                           g_io_channel_error_from_errno (errsv),
332
0
                           g_strerror (errsv));
333
0
      return G_IO_STATUS_ERROR;
334
0
    }
335
336
0
  return G_IO_STATUS_NORMAL;
337
0
}
338
339
static void 
340
g_io_unix_free (GIOChannel *channel)
341
0
{
342
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
343
344
0
  g_free (unix_channel);
345
0
}
346
347
static GSource *
348
g_io_unix_create_watch (GIOChannel   *channel,
349
      GIOCondition  condition)
350
0
{
351
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
352
0
  GSource *source;
353
0
  GIOUnixWatch *watch;
354
355
356
0
  source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
357
0
  g_source_set_static_name (source, "GIOChannel (Unix)");
358
0
  watch = (GIOUnixWatch *)source;
359
  
360
0
  watch->channel = channel;
361
0
  g_io_channel_ref (channel);
362
  
363
0
  watch->condition = condition;
364
365
0
  watch->pollfd.fd = unix_channel->fd;
366
0
  watch->pollfd.events = condition;
367
368
0
  g_source_add_poll (source, &watch->pollfd);
369
370
0
  return source;
371
0
}
372
373
static GIOStatus
374
g_io_unix_set_flags (GIOChannel *channel,
375
                     GIOFlags    flags,
376
                     GError    **err)
377
0
{
378
0
  glong fcntl_flags;
379
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
380
381
0
  fcntl_flags = 0;
382
383
0
  if (flags & G_IO_FLAG_APPEND)
384
0
    fcntl_flags |= O_APPEND;
385
0
  if (flags & G_IO_FLAG_NONBLOCK)
386
0
#ifdef O_NONBLOCK
387
0
    fcntl_flags |= O_NONBLOCK;
388
#else
389
    fcntl_flags |= O_NDELAY;
390
#endif
391
392
0
  if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
393
0
    {
394
0
      int errsv = errno;
395
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
396
0
                           g_io_channel_error_from_errno (errsv),
397
0
                           g_strerror (errsv));
398
0
      return G_IO_STATUS_ERROR;
399
0
    }
400
401
0
  return G_IO_STATUS_NORMAL;
402
0
}
403
404
static GIOFlags
405
g_io_unix_get_flags (GIOChannel *channel)
406
0
{
407
0
  GIOFlags flags = G_IO_FLAG_NONE;
408
0
  glong fcntl_flags;
409
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
410
411
0
  fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
412
413
0
  if (fcntl_flags == -1)
414
0
    {
415
0
      int err = errno;
416
0
      g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)",
417
0
     g_strerror (err), err);
418
0
      return 0;
419
0
    }
420
421
0
  if (fcntl_flags & O_APPEND)
422
0
    flags |= G_IO_FLAG_APPEND;
423
0
#ifdef O_NONBLOCK
424
0
  if (fcntl_flags & O_NONBLOCK)
425
#else
426
  if (fcntl_flags & O_NDELAY)
427
#endif
428
0
    flags |= G_IO_FLAG_NONBLOCK;
429
430
0
  switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
431
0
    {
432
0
      case O_RDONLY:
433
0
        channel->is_readable = TRUE;
434
0
        channel->is_writeable = FALSE;
435
0
        break;
436
0
      case O_WRONLY:
437
0
        channel->is_readable = FALSE;
438
0
        channel->is_writeable = TRUE;
439
0
        break;
440
0
      case O_RDWR:
441
0
        channel->is_readable = TRUE;
442
0
        channel->is_writeable = TRUE;
443
0
        break;
444
0
      default:
445
0
        g_assert_not_reached ();
446
0
    }
447
448
0
  return flags;
449
0
}
450
451
GIOChannel *
452
g_io_channel_new_file (const gchar *filename,
453
                       const gchar *mode,
454
                       GError     **error)
455
0
{
456
0
  int fid, flags;
457
0
  mode_t create_mode;
458
0
  GIOChannel *channel;
459
0
  enum { /* Cheesy hack */
460
0
    MODE_R = 1 << 0,
461
0
    MODE_W = 1 << 1,
462
0
    MODE_A = 1 << 2,
463
0
    MODE_PLUS = 1 << 3,
464
0
    MODE_R_PLUS = MODE_R | MODE_PLUS,
465
0
    MODE_W_PLUS = MODE_W | MODE_PLUS,
466
0
    MODE_A_PLUS = MODE_A | MODE_PLUS
467
0
  } mode_num;
468
0
  struct stat buffer;
469
470
0
  g_return_val_if_fail (filename != NULL, NULL);
471
0
  g_return_val_if_fail (mode != NULL, NULL);
472
0
  g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
473
474
0
  switch (mode[0])
475
0
    {
476
0
      case 'r':
477
0
        mode_num = MODE_R;
478
0
        break;
479
0
      case 'w':
480
0
        mode_num = MODE_W;
481
0
        break;
482
0
      case 'a':
483
0
        mode_num = MODE_A;
484
0
        break;
485
0
      default:
486
0
        g_warning ("Invalid GIOFileMode %s.", mode);
487
0
        return NULL;
488
0
    }
489
490
0
  switch (mode[1])
491
0
    {
492
0
      case '\0':
493
0
        break;
494
0
      case '+':
495
0
        if (mode[2] == '\0')
496
0
          {
497
0
            mode_num |= MODE_PLUS;
498
0
            break;
499
0
          }
500
0
        G_GNUC_FALLTHROUGH;
501
0
      default:
502
0
        g_warning ("Invalid GIOFileMode %s.", mode);
503
0
        return NULL;
504
0
    }
505
506
0
  switch (mode_num)
507
0
    {
508
0
      case MODE_R:
509
0
        flags = O_RDONLY;
510
0
        break;
511
0
      case MODE_W:
512
0
        flags = O_WRONLY | O_TRUNC | O_CREAT;
513
0
        break;
514
0
      case MODE_A:
515
0
        flags = O_WRONLY | O_APPEND | O_CREAT;
516
0
        break;
517
0
      case MODE_R_PLUS:
518
0
        flags = O_RDWR;
519
0
        break;
520
0
      case MODE_W_PLUS:
521
0
        flags = O_RDWR | O_TRUNC | O_CREAT;
522
0
        break;
523
0
      case MODE_A_PLUS:
524
0
        flags = O_RDWR | O_APPEND | O_CREAT;
525
0
        break;
526
0
      case MODE_PLUS:
527
0
      default:
528
0
        g_assert_not_reached ();
529
0
        flags = 0;
530
0
    }
531
532
0
  create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
533
534
0
  fid = g_open (filename, flags | O_CLOEXEC, create_mode);
535
0
  if (fid == -1)
536
0
    {
537
0
      int err = errno;
538
0
      g_set_error_literal (error, G_FILE_ERROR,
539
0
                           g_file_error_from_errno (err),
540
0
                           g_strerror (err));
541
0
      return (GIOChannel *)NULL;
542
0
    }
543
544
0
  if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
545
0
    {
546
0
      int err = errno;
547
0
      close (fid);
548
0
      g_set_error_literal (error, G_FILE_ERROR,
549
0
                           g_file_error_from_errno (err),
550
0
                           g_strerror (err));
551
0
      return (GIOChannel *)NULL;
552
0
    }
553
554
0
  channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
555
556
0
  channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
557
0
                         || S_ISBLK (buffer.st_mode);
558
559
0
  switch (mode_num)
560
0
    {
561
0
      case MODE_R:
562
0
        channel->is_readable = TRUE;
563
0
        channel->is_writeable = FALSE;
564
0
        break;
565
0
      case MODE_W:
566
0
      case MODE_A:
567
0
        channel->is_readable = FALSE;
568
0
        channel->is_writeable = TRUE;
569
0
        break;
570
0
      case MODE_R_PLUS:
571
0
      case MODE_W_PLUS:
572
0
      case MODE_A_PLUS:
573
0
        channel->is_readable = TRUE;
574
0
        channel->is_writeable = TRUE;
575
0
        break;
576
0
      case MODE_PLUS:
577
0
      default:
578
0
        g_assert_not_reached ();
579
0
    }
580
581
0
  g_io_channel_init (channel);
582
0
  channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
583
0
  channel->funcs = &unix_channel_funcs;
584
585
0
  ((GIOUnixChannel *) channel)->fd = fid;
586
0
  return channel;
587
0
}
588
589
/**
590
 * g_io_channel_unix_new:
591
 * @fd: a file descriptor.
592
 *
593
 * Creates a new #GIOChannel given a file descriptor. On UNIX systems
594
 * this works for plain files, pipes, and sockets.
595
 *
596
 * The returned #GIOChannel has a reference count of 1.
597
 *
598
 * The default encoding for #GIOChannel is UTF-8. If your application
599
 * is reading output from a command using via pipe, you may need to set
600
 * the encoding to the encoding of the current locale (see
601
 * g_get_charset()) with the g_io_channel_set_encoding() function.
602
 * By default, the fd passed will not be closed when the final reference
603
 * to the #GIOChannel data structure is dropped.
604
 *
605
 * If you want to read raw binary data without interpretation, then
606
 * call the g_io_channel_set_encoding() function with %NULL for the
607
 * encoding argument.
608
 *
609
 * This function is available in GLib on Windows, too, but you should
610
 * avoid using it on Windows. The domain of file descriptors and
611
 * sockets overlap. There is no way for GLib to know which one you mean
612
 * in case the argument you pass to this function happens to be both a
613
 * valid file descriptor and socket. If that happens a warning is
614
 * issued, and GLib assumes that it is the file descriptor you mean.
615
 *
616
 * Returns: a new #GIOChannel.
617
 **/
618
GIOChannel *
619
g_io_channel_unix_new (gint fd)
620
0
{
621
0
  struct stat buffer;
622
0
  GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
623
0
  GIOChannel *channel = (GIOChannel *)unix_channel;
624
625
0
  g_io_channel_init (channel);
626
0
  channel->funcs = &unix_channel_funcs;
627
628
0
  unix_channel->fd = fd;
629
630
  /* I'm not sure if fstat on a non-file (e.g., socket) works
631
   * it should be safe to say if it fails, the fd isn't seekable.
632
   */
633
  /* Newer UNIX versions support S_ISSOCK(), fstat() will probably
634
   * succeed in most cases.
635
   */
636
0
  if (fstat (unix_channel->fd, &buffer) == 0)
637
0
    channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
638
0
                           || S_ISBLK (buffer.st_mode);
639
0
  else /* Assume not seekable */
640
0
    channel->is_seekable = FALSE;
641
642
0
  g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
643
644
0
  return channel;
645
0
}
646
647
/**
648
 * g_io_channel_unix_get_fd:
649
 * @channel: a #GIOChannel, created with g_io_channel_unix_new().
650
 *
651
 * Returns the file descriptor of the #GIOChannel.
652
 *
653
 * On Windows this function returns the file descriptor or socket of
654
 * the #GIOChannel.
655
 *
656
 * Returns: the file descriptor of the #GIOChannel.
657
 **/
658
gint
659
g_io_channel_unix_get_fd (GIOChannel *channel)
660
0
{
661
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
662
0
  return unix_channel->fd;
663
0
}