Coverage Report

Created: 2025-11-16 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib-2.80.0/glib/giounix.c
Line
Count
Source
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
  /* Only return TRUE here if _all_ bits in watch->condition will be set
139
   */
140
0
  return ((watch->condition & buffer_condition) == watch->condition);
141
0
}
142
143
static gboolean 
144
g_io_unix_check (GSource  *source)
145
0
{
146
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
147
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
148
0
  GIOCondition poll_condition = watch->pollfd.revents;
149
150
0
  return ((poll_condition | buffer_condition) & watch->condition);
151
0
}
152
153
static gboolean
154
g_io_unix_dispatch (GSource     *source,
155
        GSourceFunc  callback,
156
        gpointer     user_data)
157
158
0
{
159
0
  GIOFunc func = (GIOFunc)callback;
160
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
161
0
  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
162
163
0
  if (!func)
164
0
    {
165
0
      g_warning ("IO watch dispatched without callback. "
166
0
     "You must call g_source_connect().");
167
0
      return FALSE;
168
0
    }
169
  
170
0
  return (*func) (watch->channel,
171
0
      (watch->pollfd.revents | buffer_condition) & watch->condition,
172
0
      user_data);
173
0
}
174
175
static void 
176
g_io_unix_finalize (GSource *source)
177
0
{
178
0
  GIOUnixWatch *watch = (GIOUnixWatch *)source;
179
180
0
  g_io_channel_unref (watch->channel);
181
0
}
182
183
static GIOStatus
184
g_io_unix_read (GIOChannel *channel, 
185
    gchar      *buf, 
186
    gsize       count,
187
    gsize      *bytes_read,
188
    GError    **err)
189
0
{
190
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
191
0
  gssize result;
192
193
0
  if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
194
0
    count = SSIZE_MAX;
195
196
0
 retry:
197
0
  result = read (unix_channel->fd, buf, count);
198
199
0
  if (result < 0)
200
0
    {
201
0
      int errsv = errno;
202
0
      *bytes_read = 0;
203
204
0
      switch (errsv)
205
0
        {
206
0
#ifdef EINTR
207
0
          case EINTR:
208
0
            goto retry;
209
0
#endif
210
0
#ifdef EAGAIN
211
0
          case EAGAIN:
212
0
            return G_IO_STATUS_AGAIN;
213
0
#endif
214
0
          default:
215
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
216
0
                                 g_io_channel_error_from_errno (errsv),
217
0
                                 g_strerror (errsv));
218
0
            return G_IO_STATUS_ERROR;
219
0
        }
220
0
    }
221
222
0
  *bytes_read = result;
223
224
0
  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
225
0
}
226
227
static GIOStatus
228
g_io_unix_write (GIOChannel  *channel, 
229
     const gchar *buf, 
230
     gsize       count,
231
     gsize      *bytes_written,
232
     GError    **err)
233
0
{
234
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
235
0
  gssize result;
236
237
0
 retry:
238
0
  result = write (unix_channel->fd, buf, count);
239
240
0
  if (result < 0)
241
0
    {
242
0
      int errsv = errno;
243
0
      *bytes_written = 0;
244
245
0
      switch (errsv)
246
0
        {
247
0
#ifdef EINTR
248
0
          case EINTR:
249
0
            goto retry;
250
0
#endif
251
0
#ifdef EAGAIN
252
0
          case EAGAIN:
253
0
            return G_IO_STATUS_AGAIN;
254
0
#endif
255
0
          default:
256
0
            g_set_error_literal (err, G_IO_CHANNEL_ERROR,
257
0
                                 g_io_channel_error_from_errno (errsv),
258
0
                                 g_strerror (errsv));
259
0
            return G_IO_STATUS_ERROR;
260
0
        }
261
0
    }
262
263
0
  *bytes_written = result;
264
265
0
  return G_IO_STATUS_NORMAL;
266
0
}
267
268
static GIOStatus
269
g_io_unix_seek (GIOChannel *channel,
270
    gint64      offset, 
271
    GSeekType   type,
272
                GError    **err)
273
0
{
274
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
275
0
  int whence;
276
0
  off_t tmp_offset;
277
0
  off_t result;
278
279
0
  switch (type)
280
0
    {
281
0
    case G_SEEK_SET:
282
0
      whence = SEEK_SET;
283
0
      break;
284
0
    case G_SEEK_CUR:
285
0
      whence = SEEK_CUR;
286
0
      break;
287
0
    case G_SEEK_END:
288
0
      whence = SEEK_END;
289
0
      break;
290
0
    default:
291
0
      whence = -1; /* Shut the compiler up */
292
0
      g_assert_not_reached ();
293
0
    }
294
295
0
  tmp_offset = offset;
296
0
  if (tmp_offset != offset)
297
0
    {
298
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
299
0
                           g_io_channel_error_from_errno (EINVAL),
300
0
                           g_strerror (EINVAL));
301
0
      return G_IO_STATUS_ERROR;
302
0
    }
303
  
304
0
  result = lseek (unix_channel->fd, tmp_offset, whence);
305
306
0
  if (result < 0)
307
0
    {
308
0
      int errsv = errno;
309
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
310
0
                           g_io_channel_error_from_errno (errsv),
311
0
                           g_strerror (errsv));
312
0
      return G_IO_STATUS_ERROR;
313
0
    }
314
315
0
  return G_IO_STATUS_NORMAL;
316
0
}
317
318
319
static GIOStatus
320
g_io_unix_close (GIOChannel *channel,
321
     GError    **err)
322
0
{
323
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
324
325
0
  if (close (unix_channel->fd) < 0)
326
0
    {
327
0
      int errsv = errno;
328
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
329
0
                           g_io_channel_error_from_errno (errsv),
330
0
                           g_strerror (errsv));
331
0
      return G_IO_STATUS_ERROR;
332
0
    }
333
334
0
  return G_IO_STATUS_NORMAL;
335
0
}
336
337
static void 
338
g_io_unix_free (GIOChannel *channel)
339
0
{
340
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
341
342
0
  g_free (unix_channel);
343
0
}
344
345
static GSource *
346
g_io_unix_create_watch (GIOChannel   *channel,
347
      GIOCondition  condition)
348
0
{
349
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
350
0
  GSource *source;
351
0
  GIOUnixWatch *watch;
352
353
354
0
  source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
355
0
  g_source_set_static_name (source, "GIOChannel (Unix)");
356
0
  watch = (GIOUnixWatch *)source;
357
  
358
0
  watch->channel = channel;
359
0
  g_io_channel_ref (channel);
360
  
361
0
  watch->condition = condition;
362
363
0
  watch->pollfd.fd = unix_channel->fd;
364
0
  watch->pollfd.events = condition;
365
366
0
  g_source_add_poll (source, &watch->pollfd);
367
368
0
  return source;
369
0
}
370
371
static GIOStatus
372
g_io_unix_set_flags (GIOChannel *channel,
373
                     GIOFlags    flags,
374
                     GError    **err)
375
0
{
376
0
  glong fcntl_flags;
377
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
378
379
0
  fcntl_flags = 0;
380
381
0
  if (flags & G_IO_FLAG_APPEND)
382
0
    fcntl_flags |= O_APPEND;
383
0
  if (flags & G_IO_FLAG_NONBLOCK)
384
0
#ifdef O_NONBLOCK
385
0
    fcntl_flags |= O_NONBLOCK;
386
#else
387
    fcntl_flags |= O_NDELAY;
388
#endif
389
390
0
  if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
391
0
    {
392
0
      int errsv = errno;
393
0
      g_set_error_literal (err, G_IO_CHANNEL_ERROR,
394
0
                           g_io_channel_error_from_errno (errsv),
395
0
                           g_strerror (errsv));
396
0
      return G_IO_STATUS_ERROR;
397
0
    }
398
399
0
  return G_IO_STATUS_NORMAL;
400
0
}
401
402
static GIOFlags
403
g_io_unix_get_flags (GIOChannel *channel)
404
0
{
405
0
  GIOFlags flags = G_IO_FLAG_NONE;
406
0
  glong fcntl_flags;
407
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
408
409
0
  fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
410
411
0
  if (fcntl_flags == -1)
412
0
    {
413
0
      int err = errno;
414
0
      g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)",
415
0
     g_strerror (err), err);
416
0
      return 0;
417
0
    }
418
419
0
  if (fcntl_flags & O_APPEND)
420
0
    flags |= G_IO_FLAG_APPEND;
421
0
#ifdef O_NONBLOCK
422
0
  if (fcntl_flags & O_NONBLOCK)
423
#else
424
  if (fcntl_flags & O_NDELAY)
425
#endif
426
0
    flags |= G_IO_FLAG_NONBLOCK;
427
428
0
  switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
429
0
    {
430
0
      case O_RDONLY:
431
0
        channel->is_readable = TRUE;
432
0
        channel->is_writeable = FALSE;
433
0
        break;
434
0
      case O_WRONLY:
435
0
        channel->is_readable = FALSE;
436
0
        channel->is_writeable = TRUE;
437
0
        break;
438
0
      case O_RDWR:
439
0
        channel->is_readable = TRUE;
440
0
        channel->is_writeable = TRUE;
441
0
        break;
442
0
      default:
443
0
        g_assert_not_reached ();
444
0
    }
445
446
0
  return flags;
447
0
}
448
449
GIOChannel *
450
g_io_channel_new_file (const gchar *filename,
451
                       const gchar *mode,
452
                       GError     **error)
453
0
{
454
0
  int fid, flags;
455
0
  mode_t create_mode;
456
0
  GIOChannel *channel;
457
0
  enum { /* Cheesy hack */
458
0
    MODE_R = 1 << 0,
459
0
    MODE_W = 1 << 1,
460
0
    MODE_A = 1 << 2,
461
0
    MODE_PLUS = 1 << 3,
462
0
    MODE_R_PLUS = MODE_R | MODE_PLUS,
463
0
    MODE_W_PLUS = MODE_W | MODE_PLUS,
464
0
    MODE_A_PLUS = MODE_A | MODE_PLUS
465
0
  } mode_num;
466
0
  struct stat buffer;
467
468
0
  g_return_val_if_fail (filename != NULL, NULL);
469
0
  g_return_val_if_fail (mode != NULL, NULL);
470
0
  g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
471
472
0
  switch (mode[0])
473
0
    {
474
0
      case 'r':
475
0
        mode_num = MODE_R;
476
0
        break;
477
0
      case 'w':
478
0
        mode_num = MODE_W;
479
0
        break;
480
0
      case 'a':
481
0
        mode_num = MODE_A;
482
0
        break;
483
0
      default:
484
0
        g_warning ("Invalid GIOFileMode %s.", mode);
485
0
        return NULL;
486
0
    }
487
488
0
  switch (mode[1])
489
0
    {
490
0
      case '\0':
491
0
        break;
492
0
      case '+':
493
0
        if (mode[2] == '\0')
494
0
          {
495
0
            mode_num |= MODE_PLUS;
496
0
            break;
497
0
          }
498
0
        G_GNUC_FALLTHROUGH;
499
0
      default:
500
0
        g_warning ("Invalid GIOFileMode %s.", mode);
501
0
        return NULL;
502
0
    }
503
504
0
  switch (mode_num)
505
0
    {
506
0
      case MODE_R:
507
0
        flags = O_RDONLY;
508
0
        break;
509
0
      case MODE_W:
510
0
        flags = O_WRONLY | O_TRUNC | O_CREAT;
511
0
        break;
512
0
      case MODE_A:
513
0
        flags = O_WRONLY | O_APPEND | O_CREAT;
514
0
        break;
515
0
      case MODE_R_PLUS:
516
0
        flags = O_RDWR;
517
0
        break;
518
0
      case MODE_W_PLUS:
519
0
        flags = O_RDWR | O_TRUNC | O_CREAT;
520
0
        break;
521
0
      case MODE_A_PLUS:
522
0
        flags = O_RDWR | O_APPEND | O_CREAT;
523
0
        break;
524
0
      case MODE_PLUS:
525
0
      default:
526
0
        g_assert_not_reached ();
527
0
        flags = 0;
528
0
    }
529
530
0
  create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
531
532
0
  fid = g_open (filename, flags | O_CLOEXEC, create_mode);
533
0
  if (fid == -1)
534
0
    {
535
0
      int err = errno;
536
0
      g_set_error_literal (error, G_FILE_ERROR,
537
0
                           g_file_error_from_errno (err),
538
0
                           g_strerror (err));
539
0
      return (GIOChannel *)NULL;
540
0
    }
541
542
0
  if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
543
0
    {
544
0
      int err = errno;
545
0
      close (fid);
546
0
      g_set_error_literal (error, G_FILE_ERROR,
547
0
                           g_file_error_from_errno (err),
548
0
                           g_strerror (err));
549
0
      return (GIOChannel *)NULL;
550
0
    }
551
552
0
  channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
553
554
0
  channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
555
0
                         || S_ISBLK (buffer.st_mode);
556
557
0
  switch (mode_num)
558
0
    {
559
0
      case MODE_R:
560
0
        channel->is_readable = TRUE;
561
0
        channel->is_writeable = FALSE;
562
0
        break;
563
0
      case MODE_W:
564
0
      case MODE_A:
565
0
        channel->is_readable = FALSE;
566
0
        channel->is_writeable = TRUE;
567
0
        break;
568
0
      case MODE_R_PLUS:
569
0
      case MODE_W_PLUS:
570
0
      case MODE_A_PLUS:
571
0
        channel->is_readable = TRUE;
572
0
        channel->is_writeable = TRUE;
573
0
        break;
574
0
      case MODE_PLUS:
575
0
      default:
576
0
        g_assert_not_reached ();
577
0
    }
578
579
0
  g_io_channel_init (channel);
580
0
  channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
581
0
  channel->funcs = &unix_channel_funcs;
582
583
0
  ((GIOUnixChannel *) channel)->fd = fid;
584
0
  return channel;
585
0
}
586
587
/**
588
 * g_io_channel_unix_new:
589
 * @fd: a file descriptor.
590
 *
591
 * Creates a new #GIOChannel given a file descriptor. On UNIX systems
592
 * this works for plain files, pipes, and sockets.
593
 *
594
 * The returned #GIOChannel has a reference count of 1.
595
 *
596
 * The default encoding for #GIOChannel is UTF-8. If your application
597
 * is reading output from a command using via pipe, you may need to set
598
 * the encoding to the encoding of the current locale (see
599
 * g_get_charset()) with the g_io_channel_set_encoding() function.
600
 * By default, the fd passed will not be closed when the final reference
601
 * to the #GIOChannel data structure is dropped.
602
 *
603
 * If you want to read raw binary data without interpretation, then
604
 * call the g_io_channel_set_encoding() function with %NULL for the
605
 * encoding argument.
606
 *
607
 * This function is available in GLib on Windows, too, but you should
608
 * avoid using it on Windows. The domain of file descriptors and
609
 * sockets overlap. There is no way for GLib to know which one you mean
610
 * in case the argument you pass to this function happens to be both a
611
 * valid file descriptor and socket. If that happens a warning is
612
 * issued, and GLib assumes that it is the file descriptor you mean.
613
 *
614
 * Returns: a new #GIOChannel.
615
 **/
616
GIOChannel *
617
g_io_channel_unix_new (gint fd)
618
0
{
619
0
  struct stat buffer;
620
0
  GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
621
0
  GIOChannel *channel = (GIOChannel *)unix_channel;
622
623
0
  g_io_channel_init (channel);
624
0
  channel->funcs = &unix_channel_funcs;
625
626
0
  unix_channel->fd = fd;
627
628
  /* I'm not sure if fstat on a non-file (e.g., socket) works
629
   * it should be safe to say if it fails, the fd isn't seekable.
630
   */
631
  /* Newer UNIX versions support S_ISSOCK(), fstat() will probably
632
   * succeed in most cases.
633
   */
634
0
  if (fstat (unix_channel->fd, &buffer) == 0)
635
0
    channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
636
0
                           || S_ISBLK (buffer.st_mode);
637
0
  else /* Assume not seekable */
638
0
    channel->is_seekable = FALSE;
639
640
0
  g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
641
642
0
  return channel;
643
0
}
644
645
/**
646
 * g_io_channel_unix_get_fd:
647
 * @channel: a #GIOChannel, created with g_io_channel_unix_new().
648
 *
649
 * Returns the file descriptor of the #GIOChannel.
650
 *
651
 * On Windows this function returns the file descriptor or socket of
652
 * the #GIOChannel.
653
 *
654
 * Returns: the file descriptor of the #GIOChannel.
655
 **/
656
gint
657
g_io_channel_unix_get_fd (GIOChannel *channel)
658
0
{
659
0
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
660
0
  return unix_channel->fd;
661
0
}