1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * giounix.c: IO Channels using unix file descriptors
5 * Copyright 1998 Owen Taylor
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.
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.
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.
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/.
35 #include <sys/types.h>
47 typedef struct _GIOUnixChannel GIOUnixChannel;
48 typedef struct _GIOUnixWatch GIOUnixWatch;
50 struct _GIOUnixChannel
61 GIOCondition condition;
66 static GIOStatus g_io_unix_read (GIOChannel *channel,
71 static GIOStatus g_io_unix_write (GIOChannel *channel,
76 static GIOStatus g_io_unix_seek (GIOChannel *channel,
80 static GIOStatus g_io_unix_close (GIOChannel *channel,
82 static void g_io_unix_free (GIOChannel *channel);
83 static GSource* g_io_unix_create_watch (GIOChannel *channel,
84 GIOCondition condition);
85 static GIOStatus g_io_unix_set_flags (GIOChannel *channel,
88 static GIOFlags g_io_unix_get_flags (GIOChannel *channel);
90 static gboolean g_io_unix_prepare (GSource *source,
92 static gboolean g_io_unix_check (GSource *source);
93 static gboolean g_io_unix_dispatch (GSource *source,
96 static void g_io_unix_destroy (GSource *source);
98 GSourceFuncs unix_watch_funcs = {
105 GIOFuncs unix_channel_funcs = {
110 g_io_unix_create_watch,
117 g_io_unix_prepare (GSource *source,
120 GIOUnixWatch *watch = (GIOUnixWatch *)source;
124 /* Only return TRUE if we're sure to match all conditions, otherwise
128 watch->condition = g_io_channel_get_buffer_condition (watch->channel);
130 return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
135 g_io_unix_check (GSource *source)
137 GIOUnixWatch *watch = (GIOUnixWatch *)source;
139 watch->condition &= g_io_channel_get_buffer_condition (watch->channel);
141 return (watch->pollfd.revents & watch->condition);
145 g_io_unix_dispatch (GSource *source,
146 GSourceFunc callback,
150 GIOFunc func = (GIOFunc)callback;
151 GIOUnixWatch *watch = (GIOUnixWatch *)source;
155 g_warning ("IO watch dispatched without callback\n"
156 "You must call g_source_connect().");
160 return (*func) (watch->channel,
161 watch->pollfd.revents & watch->condition,
166 g_io_unix_destroy (GSource *source)
168 GIOUnixWatch *watch = (GIOUnixWatch *)source;
170 g_io_channel_unref (watch->channel);
174 g_io_unix_read (GIOChannel *channel,
180 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
184 result = read (unix_channel->fd, buf, count);
198 return G_IO_STATUS_AGAIN;
201 g_set_error (err, G_IO_CHANNEL_ERROR,
202 g_channel_error_from_errno (errno),
204 return G_IO_STATUS_ERROR;
208 *bytes_read = result;
210 return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
214 g_io_unix_write (GIOChannel *channel,
217 gsize *bytes_written,
220 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
224 result = write (unix_channel->fd, buf, count);
238 return G_IO_STATUS_AGAIN;
241 g_set_error (err, G_IO_CHANNEL_ERROR,
242 g_channel_error_from_errno (errno),
244 return G_IO_STATUS_ERROR;
248 *bytes_written = result;
250 return G_IO_STATUS_NORMAL;
254 g_io_unix_seek (GIOChannel *channel,
259 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
275 whence = -1; /* Shut the compiler up */
276 g_assert_not_reached ();
279 result = lseek (unix_channel->fd, offset, whence);
283 g_set_error (err, G_IO_CHANNEL_ERROR,
284 g_channel_error_from_errno (errno),
286 return G_IO_STATUS_ERROR;
289 return G_IO_STATUS_NORMAL;
294 g_io_unix_close (GIOChannel *channel,
297 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
299 if (close (unix_channel->fd) < 0)
301 g_set_error (err, G_IO_CHANNEL_ERROR,
302 g_channel_error_from_errno (errno),
304 return G_IO_STATUS_ERROR;
307 return G_IO_STATUS_NORMAL;
311 g_io_unix_free (GIOChannel *channel)
313 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
315 g_free (unix_channel);
319 g_io_unix_create_watch (GIOChannel *channel,
320 GIOCondition condition)
322 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
327 source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
328 watch = (GIOUnixWatch *)source;
330 watch->channel = channel;
331 g_io_channel_ref (channel);
333 watch->condition = condition;
335 watch->pollfd.fd = unix_channel->fd;
336 watch->pollfd.events = condition;
338 g_source_add_poll (source, &watch->pollfd);
343 static const GIOFlags g_io_unix_fcntl_flags[] = {
347 static const glong g_io_unix_fcntl_posix_flags[] = {
355 #define G_IO_UNIX_NUM_FCNTL_FLAGS G_N_ELEMENTS (g_io_unix_fcntl_flags)
357 static const GIOFlags g_io_unix_fcntl_flags_read_only[] = {
358 G_IO_FLAG_IS_READABLE,
359 G_IO_FLAG_IS_WRITEABLE,
361 static const glong g_io_unix_fcntl_posix_flags_read_only[] = {
365 /* Only need to map posix_flags -> flags for read only, not the
366 * other way around, so this works.
368 #define G_IO_UNIX_NUM_FCNTL_FLAGS_READ_ONLY G_N_ELEMENTS (g_io_unix_fcntl_flags_read_only)
371 g_io_unix_set_flags (GIOChannel *channel,
377 GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
381 for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS; loop++)
382 if (flags & g_io_unix_fcntl_flags[loop])
383 fcntl_flags |= g_io_unix_fcntl_posix_flags[loop];
385 if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
387 g_set_error (err, G_IO_CHANNEL_ERROR,
388 g_channel_error_from_errno (errno),
390 return G_IO_STATUS_ERROR;
393 return G_IO_STATUS_NORMAL;
397 g_io_unix_get_flags (GIOChannel *channel)
402 GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
405 fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
406 if (fcntl_flags == -1)
408 g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)\n",
409 g_strerror (errno), errno);
412 if (!channel->seekable_cached)
414 channel->seekable_cached = TRUE;
416 /* I'm not sure if fstat on a non-file (e.g., socket) works
417 * it should be safe to sat if it fails, the fd isn't seekable.
419 if (fstat (unix_channel->fd, &buffer) == -1 ||
420 !S_ISREG (buffer.st_mode))
421 channel->is_seekable = FALSE;
423 channel->is_seekable = TRUE;
426 for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS; loop++)
427 if (fcntl_flags & g_io_unix_fcntl_posix_flags[loop])
428 flags |= g_io_unix_fcntl_flags[loop];
430 for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS_READ_ONLY; loop++)
431 if (fcntl_flags & g_io_unix_fcntl_posix_flags_read_only[loop])
432 flags |= g_io_unix_fcntl_flags_read_only[loop];
434 if (channel->is_seekable)
435 flags |= G_IO_FLAG_IS_SEEKABLE;
441 g_io_channel_new_file (const gchar *filename,
452 case G_IO_FILE_MODE_READ:
455 case G_IO_FILE_MODE_WRITE:
458 case G_IO_FILE_MODE_APPEND:
461 case G_IO_FILE_MODE_READ_WRITE:
464 case G_IO_FILE_MODE_READ_WRITE_TRUNCATE:
467 case G_IO_FILE_MODE_READ_WRITE_APPEND:
471 g_warning ("Invalid GIOFileMode %i.\n", mode);
475 f = fopen (filename, mode_name);
478 g_set_error (error, G_FILE_ERROR,
479 g_file_error_from_errno (errno),
481 return (GIOChannel *)NULL;
486 channel = g_io_channel_unix_new (fid);
487 channel->close_on_unref = TRUE;
492 g_io_channel_unix_new (gint fd)
494 GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
495 GIOChannel *channel = (GIOChannel *)unix_channel;
497 g_io_channel_init (channel);
498 channel->funcs = &unix_channel_funcs;
500 unix_channel->fd = fd;
505 g_io_channel_unix_get_fd (GIOChannel *channel)
507 GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
508 return unix_channel->fd;