source: trunk/third/glib2/glib/giounix.c @ 20721

Revision 20721, 14.1 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
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 * 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 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 Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
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
46#include "glib.h"
47
48/*
49 * Unix IO Channels
50 */
51
52typedef struct _GIOUnixChannel GIOUnixChannel;
53typedef struct _GIOUnixWatch GIOUnixWatch;
54
55struct _GIOUnixChannel
56{
57  GIOChannel channel;
58  gint fd;
59};
60
61struct _GIOUnixWatch
62{
63  GSource       source;
64  GPollFD       pollfd;
65  GIOChannel   *channel;
66  GIOCondition  condition;
67};
68
69
70static GIOStatus        g_io_unix_read          (GIOChannel   *channel,
71                                                 gchar        *buf,
72                                                 gsize         count,
73                                                 gsize        *bytes_read,
74                                                 GError      **err);
75static GIOStatus        g_io_unix_write         (GIOChannel   *channel,
76                                                 const gchar  *buf,
77                                                 gsize         count,
78                                                 gsize        *bytes_written,
79                                                 GError      **err);
80static GIOStatus        g_io_unix_seek          (GIOChannel   *channel,
81                                                 gint64        offset,
82                                                 GSeekType     type,
83                                                 GError      **err);
84static GIOStatus        g_io_unix_close         (GIOChannel   *channel,
85                                                 GError      **err);
86static void             g_io_unix_free          (GIOChannel   *channel);
87static GSource*         g_io_unix_create_watch  (GIOChannel   *channel,
88                                                 GIOCondition  condition);
89static GIOStatus        g_io_unix_set_flags     (GIOChannel   *channel,
90                                                 GIOFlags      flags,
91                                                 GError      **err);
92static GIOFlags         g_io_unix_get_flags     (GIOChannel   *channel);
93
94static gboolean g_io_unix_prepare  (GSource     *source,
95                                    gint        *timeout);
96static gboolean g_io_unix_check    (GSource     *source);
97static gboolean g_io_unix_dispatch (GSource     *source,
98                                    GSourceFunc  callback,
99                                    gpointer     user_data);
100static void     g_io_unix_finalize (GSource     *source);
101
102GSourceFuncs g_io_watch_funcs = {
103  g_io_unix_prepare,
104  g_io_unix_check,
105  g_io_unix_dispatch,
106  g_io_unix_finalize
107};
108
109static GIOFuncs unix_channel_funcs = {
110  g_io_unix_read,
111  g_io_unix_write,
112  g_io_unix_seek,
113  g_io_unix_close,
114  g_io_unix_create_watch,
115  g_io_unix_free,
116  g_io_unix_set_flags,
117  g_io_unix_get_flags,
118};
119
120static gboolean
121g_io_unix_prepare (GSource  *source,
122                   gint     *timeout)
123{
124  GIOUnixWatch *watch = (GIOUnixWatch *)source;
125  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
126
127  *timeout = -1;
128
129  /* Only return TRUE here if _all_ bits in watch->condition will be set
130   */
131  return ((watch->condition & buffer_condition) == watch->condition);
132}
133
134static gboolean
135g_io_unix_check (GSource  *source)
136{
137  GIOUnixWatch *watch = (GIOUnixWatch *)source;
138  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
139  GIOCondition poll_condition = watch->pollfd.revents;
140
141  return ((poll_condition | buffer_condition) & watch->condition);
142}
143
144static gboolean
145g_io_unix_dispatch (GSource     *source,
146                    GSourceFunc  callback,
147                    gpointer     user_data)
148
149{
150  GIOFunc func = (GIOFunc)callback;
151  GIOUnixWatch *watch = (GIOUnixWatch *)source;
152  GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
153
154  if (!func)
155    {
156      g_warning ("IO watch dispatched without callback\n"
157                 "You must call g_source_connect().");
158      return FALSE;
159    }
160 
161  return (*func) (watch->channel,
162                  (watch->pollfd.revents | buffer_condition) & watch->condition,
163                  user_data);
164}
165
166static void
167g_io_unix_finalize (GSource *source)
168{
169  GIOUnixWatch *watch = (GIOUnixWatch *)source;
170
171  g_io_channel_unref (watch->channel);
172}
173
174static GIOStatus
175g_io_unix_read (GIOChannel *channel,
176                gchar      *buf,
177                gsize       count,
178                gsize      *bytes_read,
179                GError    **err)
180{
181  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
182  gssize result;
183
184  if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
185    count = SSIZE_MAX;
186
187 retry:
188  result = read (unix_channel->fd, buf, count);
189
190  if (result < 0)
191    {
192      *bytes_read = 0;
193
194      switch (errno)
195        {
196#ifdef EINTR
197          case EINTR:
198            goto retry;
199#endif
200#ifdef EAGAIN
201          case EAGAIN:
202            return G_IO_STATUS_AGAIN;
203#endif
204          default:
205            g_set_error (err, G_IO_CHANNEL_ERROR,
206                         g_io_channel_error_from_errno (errno),
207                         g_strerror (errno));
208            return G_IO_STATUS_ERROR;
209        }
210    }
211
212  *bytes_read = result;
213
214  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
215}
216
217static GIOStatus
218g_io_unix_write (GIOChannel  *channel,
219                 const gchar *buf,
220                 gsize       count,
221                 gsize      *bytes_written,
222                 GError    **err)
223{
224  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
225  gssize result;
226
227 retry:
228  result = write (unix_channel->fd, buf, count);
229
230  if (result < 0)
231    {
232      *bytes_written = 0;
233
234      switch (errno)
235        {
236#ifdef EINTR
237          case EINTR:
238            goto retry;
239#endif
240#ifdef EAGAIN
241          case EAGAIN:
242            return G_IO_STATUS_AGAIN;
243#endif
244          default:
245            g_set_error (err, G_IO_CHANNEL_ERROR,
246                         g_io_channel_error_from_errno (errno),
247                         g_strerror (errno));
248            return G_IO_STATUS_ERROR;
249        }
250    }
251
252  *bytes_written = result;
253
254  return G_IO_STATUS_NORMAL;
255}
256
257static GIOStatus
258g_io_unix_seek (GIOChannel *channel,
259                gint64      offset,
260                GSeekType   type,
261                GError    **err)
262{
263  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
264  int whence;
265  off_t tmp_offset;
266  off_t result;
267
268  switch (type)
269    {
270    case G_SEEK_SET:
271      whence = SEEK_SET;
272      break;
273    case G_SEEK_CUR:
274      whence = SEEK_CUR;
275      break;
276    case G_SEEK_END:
277      whence = SEEK_END;
278      break;
279    default:
280      whence = -1; /* Shut the compiler up */
281      g_assert_not_reached ();
282    }
283
284  tmp_offset = offset;
285  if (tmp_offset != offset)
286    {
287      g_set_error (err, G_IO_CHANNEL_ERROR,
288                   g_io_channel_error_from_errno (EINVAL),
289                   g_strerror (EINVAL));
290      return G_IO_STATUS_ERROR;
291    }
292 
293  result = lseek (unix_channel->fd, tmp_offset, whence);
294
295  if (result < 0)
296    {
297      g_set_error (err, G_IO_CHANNEL_ERROR,
298                   g_io_channel_error_from_errno (errno),
299                   g_strerror (errno));
300      return G_IO_STATUS_ERROR;
301    }
302
303  return G_IO_STATUS_NORMAL;
304}
305
306
307static GIOStatus
308g_io_unix_close (GIOChannel *channel,
309                 GError    **err)
310{
311  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
312
313  if (close (unix_channel->fd) < 0)
314    {
315      g_set_error (err, G_IO_CHANNEL_ERROR,
316                   g_io_channel_error_from_errno (errno),
317                   g_strerror (errno));
318      return G_IO_STATUS_ERROR;
319    }
320
321  return G_IO_STATUS_NORMAL;
322}
323
324static void
325g_io_unix_free (GIOChannel *channel)
326{
327  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
328
329  g_free (unix_channel);
330}
331
332static GSource *
333g_io_unix_create_watch (GIOChannel   *channel,
334                        GIOCondition  condition)
335{
336  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
337  GSource *source;
338  GIOUnixWatch *watch;
339
340
341  source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
342  watch = (GIOUnixWatch *)source;
343 
344  watch->channel = channel;
345  g_io_channel_ref (channel);
346 
347  watch->condition = condition;
348
349  watch->pollfd.fd = unix_channel->fd;
350  watch->pollfd.events = condition;
351
352  g_source_add_poll (source, &watch->pollfd);
353
354  return source;
355}
356
357static GIOStatus
358g_io_unix_set_flags (GIOChannel *channel,
359                     GIOFlags    flags,
360                     GError    **err)
361{
362  glong fcntl_flags;
363  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
364
365  fcntl_flags = 0;
366
367  if (flags & G_IO_FLAG_APPEND)
368    fcntl_flags |= O_APPEND;
369  if (flags & G_IO_FLAG_NONBLOCK)
370#ifdef O_NONBLOCK
371    fcntl_flags |= O_NONBLOCK;
372#else
373    fcntl_flags |= O_NDELAY;
374#endif
375
376  if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
377    {
378      g_set_error (err, G_IO_CHANNEL_ERROR,
379                   g_io_channel_error_from_errno (errno),
380                   g_strerror (errno));
381      return G_IO_STATUS_ERROR;
382    }
383
384  return G_IO_STATUS_NORMAL;
385}
386
387static GIOFlags
388g_io_unix_get_flags (GIOChannel *channel)
389{
390  GIOFlags flags = 0;
391  glong fcntl_flags;
392  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
393
394  fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
395
396  if (fcntl_flags == -1)
397    {
398      g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)\n",
399                 g_strerror (errno), errno);
400      return 0;
401    }
402
403  if (fcntl_flags & O_APPEND)
404    flags |= G_IO_FLAG_APPEND;
405#ifdef O_NONBLOCK
406  if (fcntl_flags & O_NONBLOCK)
407#else
408  if (fcntl_flags & O_NDELAY)
409#endif
410    flags |= G_IO_FLAG_NONBLOCK;
411
412  switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
413    {
414      case O_RDONLY:
415        channel->is_readable = TRUE;
416        channel->is_writeable = FALSE;
417        break;
418      case O_WRONLY:
419        channel->is_readable = FALSE;
420        channel->is_writeable = TRUE;
421        break;
422      case O_RDWR:
423        channel->is_readable = TRUE;
424        channel->is_writeable = TRUE;
425        break;
426      default:
427        g_assert_not_reached ();
428    }
429
430  return flags;
431}
432
433GIOChannel *
434g_io_channel_new_file (const gchar *filename,
435                       const gchar *mode,
436                       GError     **error)
437{
438  int fid, flags;
439  mode_t create_mode;
440  GIOChannel *channel;
441  enum { /* Cheesy hack */
442    MODE_R = 1 << 0,
443    MODE_W = 1 << 1,
444    MODE_A = 1 << 2,
445    MODE_PLUS = 1 << 3
446  } mode_num;
447  struct stat buffer;
448
449  g_return_val_if_fail (filename != NULL, NULL);
450  g_return_val_if_fail (mode != NULL, NULL);
451  g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
452
453  switch (mode[0])
454    {
455      case 'r':
456        mode_num = MODE_R;
457        break;
458      case 'w':
459        mode_num = MODE_W;
460        break;
461      case 'a':
462        mode_num = MODE_A;
463        break;
464      default:
465        g_warning ("Invalid GIOFileMode %s.\n", mode);
466        return NULL;
467    }
468
469  switch (mode[1])
470    {
471      case '\0':
472        break;
473      case '+':
474        if (mode[2] == '\0')
475          {
476            mode_num |= MODE_PLUS;
477            break;
478          }
479        /* Fall through */
480      default:
481        g_warning ("Invalid GIOFileMode %s.\n", mode);
482        return NULL;
483    }
484
485  switch (mode_num)
486    {
487      case MODE_R:
488        flags = O_RDONLY;
489        break;
490      case MODE_W:
491        flags = O_WRONLY | O_TRUNC | O_CREAT;
492        break;
493      case MODE_A:
494        flags = O_WRONLY | O_APPEND | O_CREAT;
495        break;
496      case MODE_R | MODE_PLUS:
497        flags = O_RDWR;
498        break;
499      case MODE_W | MODE_PLUS:
500        flags = O_RDWR | O_TRUNC | O_CREAT;
501        break;
502      case MODE_A | MODE_PLUS:
503        flags = O_RDWR | O_APPEND | O_CREAT;
504        break;
505      default:
506        g_assert_not_reached ();
507        flags = 0;
508    }
509
510  create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
511  fid = open (filename, flags, create_mode);
512  if (fid == -1)
513    {
514      g_set_error (error, G_FILE_ERROR,
515                   g_file_error_from_errno (errno),
516                   g_strerror (errno));
517      return (GIOChannel *)NULL;
518    }
519
520  if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
521    {
522      close (fid);
523      g_set_error (error, G_FILE_ERROR,
524                   g_file_error_from_errno (errno),
525                   g_strerror (errno));
526      return (GIOChannel *)NULL;
527    }
528
529  channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
530
531  channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
532                         || S_ISBLK (buffer.st_mode);
533
534  switch (mode_num)
535    {
536      case MODE_R:
537        channel->is_readable = TRUE;
538        channel->is_writeable = FALSE;
539        break;
540      case MODE_W:
541      case MODE_A:
542        channel->is_readable = FALSE;
543        channel->is_writeable = TRUE;
544        break;
545      case MODE_R | MODE_PLUS:
546      case MODE_W | MODE_PLUS:
547      case MODE_A | MODE_PLUS:
548        channel->is_readable = TRUE;
549        channel->is_writeable = TRUE;
550        break;
551      default:
552        g_assert_not_reached ();
553    }
554
555  g_io_channel_init (channel);
556  channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
557  channel->funcs = &unix_channel_funcs;
558
559  ((GIOUnixChannel *) channel)->fd = fid;
560  return channel;
561}
562
563GIOChannel *
564g_io_channel_unix_new (gint fd)
565{
566  struct stat buffer;
567  GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
568  GIOChannel *channel = (GIOChannel *)unix_channel;
569
570  g_io_channel_init (channel);
571  channel->funcs = &unix_channel_funcs;
572
573  unix_channel->fd = fd;
574
575  /* I'm not sure if fstat on a non-file (e.g., socket) works
576   * it should be safe to say if it fails, the fd isn't seekable.
577   */
578  /* Newer UNIX versions support S_ISSOCK(), fstat() will probably
579   * succeed in most cases.
580   */
581  if (fstat (unix_channel->fd, &buffer) == 0)
582    channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
583                           || S_ISBLK (buffer.st_mode);
584  else /* Assume not seekable */
585    channel->is_seekable = FALSE;
586
587  g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
588
589  return channel;
590}
591
592gint
593g_io_channel_unix_get_fd (GIOChannel *channel)
594{
595  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
596  return unix_channel->fd;
597}
Note: See TracBrowser for help on using the repository browser.