0bafcbbee16ccabb19481e044c04e15eb8028cd7
[platform/upstream/glib.git] / glib / giounix.c
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 "glib.h"
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <fcntl.h>
42
43 /*
44  * Unix IO Channels
45  */
46
47 typedef struct _GIOUnixChannel GIOUnixChannel;
48 typedef struct _GIOUnixWatch GIOUnixWatch;
49
50 struct _GIOUnixChannel
51 {
52   GIOChannel channel;
53   gint fd;
54 };
55
56 struct _GIOUnixWatch
57 {
58   GSource       source;
59   GPollFD       pollfd;
60   GIOChannel   *channel;
61   GIOCondition  condition;
62   GIOFunc       callback;
63 };
64
65
66 static GIOStatus        g_io_unix_read          (GIOChannel   *channel,
67                                                  gchar        *buf,
68                                                  gsize         count,
69                                                  gsize        *bytes_read,
70                                                  GError      **err);
71 static GIOStatus        g_io_unix_write         (GIOChannel   *channel,
72                                                  const gchar  *buf,
73                                                  gsize         count,
74                                                  gsize        *bytes_written,
75                                                  GError      **err);
76 static GIOStatus        g_io_unix_seek          (GIOChannel   *channel,
77                                                  glong         offset,
78                                                  GSeekType     type,
79                                                  GError      **err);
80 static GIOStatus        g_io_unix_close         (GIOChannel   *channel,
81                                                  GError      **err);
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,
86                                                  GIOFlags      flags,
87                                                  GError      **err);
88 static GIOFlags         g_io_unix_get_flags     (GIOChannel   *channel);
89
90 static gboolean g_io_unix_prepare  (GSource     *source,
91                                     gint        *timeout);
92 static gboolean g_io_unix_check    (GSource     *source);
93 static gboolean g_io_unix_dispatch (GSource     *source,
94                                     GSourceFunc  callback,
95                                     gpointer     user_data);
96 static void     g_io_unix_destroy  (GSource     *source);
97
98 GSourceFuncs unix_watch_funcs = {
99   g_io_unix_prepare,
100   g_io_unix_check,
101   g_io_unix_dispatch,
102   g_io_unix_destroy
103 };
104
105 GIOFuncs unix_channel_funcs = {
106   g_io_unix_read,
107   g_io_unix_write,
108   g_io_unix_seek,
109   g_io_unix_close,
110   g_io_unix_create_watch,
111   g_io_unix_free,
112   g_io_unix_set_flags,
113   g_io_unix_get_flags,
114 };
115
116 static gboolean 
117 g_io_unix_prepare (GSource  *source,
118                    gint     *timeout)
119 {
120   GIOUnixWatch *watch = (GIOUnixWatch *)source;
121
122   *timeout = -1;
123
124   /* Only return TRUE if we're sure to match all conditions, otherwise
125    * we need to check.
126    */
127
128   watch->condition = g_io_channel_get_buffer_condition (watch->channel);
129
130   return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
131
132 }
133
134 static gboolean 
135 g_io_unix_check (GSource  *source)
136 {
137   GIOUnixWatch *watch = (GIOUnixWatch *)source;
138
139   watch->condition &= g_io_channel_get_buffer_condition (watch->channel);
140
141   return (watch->pollfd.revents & watch->condition);
142 }
143
144 static gboolean
145 g_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
153   if (!func)
154     {
155       g_warning ("IO watch dispatched without callback\n"
156                  "You must call g_source_connect().");
157       return FALSE;
158     }
159   
160   return (*func) (watch->channel,
161                   watch->pollfd.revents & watch->condition,
162                   user_data);
163 }
164
165 static void 
166 g_io_unix_destroy (GSource *source)
167 {
168   GIOUnixWatch *watch = (GIOUnixWatch *)source;
169
170   g_io_channel_unref (watch->channel);
171 }
172
173 static GIOStatus
174 g_io_unix_read (GIOChannel *channel, 
175                 gchar      *buf, 
176                 gsize       count,
177                 gsize      *bytes_read,
178                 GError    **err)
179 {
180   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
181   gssize result;
182
183  retry:
184   result = read (unix_channel->fd, buf, count);
185
186   if (result < 0)
187     {
188       *bytes_read = 0;
189
190       switch (errno)
191         {
192 #ifdef EINTR
193           case EINTR:
194             goto retry;
195 #endif
196 #ifdef EAGAIN
197           case EAGAIN:
198             return G_IO_STATUS_AGAIN;
199 #endif
200           default:
201             g_set_error (err, G_IO_CHANNEL_ERROR,
202                          g_channel_error_from_errno (errno),
203                          strerror (errno));
204             return G_IO_STATUS_ERROR;
205         }
206     }
207
208   *bytes_read = result;
209
210   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
211 }
212
213 static GIOStatus
214 g_io_unix_write (GIOChannel  *channel, 
215                  const gchar *buf, 
216                  gsize       count,
217                  gsize      *bytes_written,
218                  GError    **err)
219 {
220   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
221   gssize result;
222
223  retry:
224   result = write (unix_channel->fd, buf, count);
225
226   if (result < 0)
227     {
228       *bytes_written = 0;
229
230       switch (errno)
231         {
232 #ifdef EINTR
233           case EINTR:
234             goto retry;
235 #endif
236 #ifdef EAGAIN
237           case EAGAIN:
238             return G_IO_STATUS_AGAIN;
239 #endif
240           default:
241             g_set_error (err, G_IO_CHANNEL_ERROR,
242                          g_channel_error_from_errno (errno),
243                          strerror (errno));
244             return G_IO_STATUS_ERROR;
245         }
246     }
247
248   *bytes_written = result;
249
250   return G_IO_STATUS_NORMAL;
251 }
252
253 static GIOStatus
254 g_io_unix_seek (GIOChannel *channel,
255                 glong       offset, 
256                 GSeekType   type,
257                 GError    **err)
258 {
259   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
260   int whence;
261   off_t result;
262
263   switch (type)
264     {
265     case G_SEEK_SET:
266       whence = SEEK_SET;
267       break;
268     case G_SEEK_CUR:
269       whence = SEEK_CUR;
270       break;
271     case G_SEEK_END:
272       whence = SEEK_END;
273       break;
274     default:
275       whence = -1; /* Shut the compiler up */
276       g_assert_not_reached ();
277     }
278
279   result = lseek (unix_channel->fd, offset, whence);
280
281   if (result < 0)
282     {
283       g_set_error (err, G_IO_CHANNEL_ERROR,
284                    g_channel_error_from_errno (errno),
285                    strerror (errno));
286       return G_IO_STATUS_ERROR;
287     }
288
289   return G_IO_STATUS_NORMAL;
290 }
291
292
293 static GIOStatus
294 g_io_unix_close (GIOChannel *channel,
295                  GError    **err)
296 {
297   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
298
299   if (close (unix_channel->fd) < 0)
300     {
301       g_set_error (err, G_IO_CHANNEL_ERROR,
302                    g_channel_error_from_errno (errno),
303                    strerror (errno));
304       return G_IO_STATUS_ERROR;
305     }
306
307   return G_IO_STATUS_NORMAL;
308 }
309
310 static void 
311 g_io_unix_free (GIOChannel *channel)
312 {
313   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
314
315   g_free (unix_channel);
316 }
317
318 static GSource *
319 g_io_unix_create_watch (GIOChannel   *channel,
320                         GIOCondition  condition)
321 {
322   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
323   GSource *source;
324   GIOUnixWatch *watch;
325
326
327   source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
328   watch = (GIOUnixWatch *)source;
329   
330   watch->channel = channel;
331   g_io_channel_ref (channel);
332   
333   watch->condition = condition;
334
335   watch->pollfd.fd = unix_channel->fd;
336   watch->pollfd.events = condition;
337
338   g_source_add_poll (source, &watch->pollfd);
339
340   return source;
341 }
342
343 static const GIOFlags g_io_unix_fcntl_flags[] = {
344   G_IO_FLAG_APPEND,
345   G_IO_FLAG_NONBLOCK,
346 };
347 static const glong g_io_unix_fcntl_posix_flags[] = {
348   O_APPEND,
349 #ifdef O_NONBLOCK
350   O_NONBLOCK,
351 #else
352   O_NDELAY,
353 #endif
354 };
355 #define G_IO_UNIX_NUM_FCNTL_FLAGS G_N_ELEMENTS (g_io_unix_fcntl_flags)
356
357 static const GIOFlags g_io_unix_fcntl_flags_read_only[] = {
358   G_IO_FLAG_IS_READABLE,
359   G_IO_FLAG_IS_WRITEABLE,
360 };
361 static const glong g_io_unix_fcntl_posix_flags_read_only[] = {
362   O_RDONLY | O_RDWR,
363   O_WRONLY | O_RDWR,
364 };
365 /* Only need to map posix_flags -> flags for read only, not the
366  * other way around, so this works.
367  */
368 #define G_IO_UNIX_NUM_FCNTL_FLAGS_READ_ONLY G_N_ELEMENTS (g_io_unix_fcntl_flags_read_only)
369
370 static GIOStatus
371 g_io_unix_set_flags (GIOChannel *channel,
372                      GIOFlags    flags,
373                      GError    **err)
374 {
375   glong fcntl_flags;
376   gint loop;
377   GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
378
379   fcntl_flags = 0;
380
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];
384
385   if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
386     {
387       g_set_error (err, G_IO_CHANNEL_ERROR,
388                    g_channel_error_from_errno (errno),
389                    g_strerror (errno));
390       return G_IO_STATUS_ERROR;
391     }
392
393   return G_IO_STATUS_NORMAL;
394 }
395
396 static GIOFlags
397 g_io_unix_get_flags (GIOChannel *channel)
398 {
399   GIOFlags flags = 0;
400   glong fcntl_flags;
401   gint loop;
402   GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
403   struct stat buffer;
404
405   fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
406   if (fcntl_flags == -1)
407     {
408       g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)\n",
409                  g_strerror (errno), errno);
410       return 0;
411     }
412   if (!channel->seekable_cached)
413     {
414       channel->seekable_cached = TRUE;
415
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.
418        */
419       if (fstat (unix_channel->fd, &buffer) == -1 ||
420           !S_ISREG (buffer.st_mode))
421         channel->is_seekable = FALSE;
422       else
423         channel->is_seekable = TRUE;
424     }
425
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];
429
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];
433
434   if (channel->is_seekable)
435     flags |= G_IO_FLAG_IS_SEEKABLE;
436
437   return flags;
438 }
439
440 GIOChannel *
441 g_io_channel_new_file (const gchar *filename,
442                        GIOFileMode  mode,
443                        GError     **error)
444 {
445   FILE *f;
446   int fid;
447   gchar *mode_name;
448   GIOChannel *channel;
449
450   switch (mode)
451     {
452       case G_IO_FILE_MODE_READ:
453         mode_name = "r";
454         break;
455       case G_IO_FILE_MODE_WRITE:
456         mode_name = "w";
457         break;
458       case G_IO_FILE_MODE_APPEND:
459         mode_name = "a";
460         break;
461       case G_IO_FILE_MODE_READ_WRITE:
462         mode_name = "r+";
463         break;
464       case G_IO_FILE_MODE_READ_WRITE_TRUNCATE:
465         mode_name = "w+";
466         break;
467       case G_IO_FILE_MODE_READ_WRITE_APPEND:
468         mode_name = "a+";
469         break;
470       default:
471         g_warning ("Invalid GIOFileMode %i.\n", mode);
472         return NULL;
473     }
474
475   f = fopen (filename, mode_name);
476   if (!f)
477     {
478       g_set_error (error, G_FILE_ERROR,
479                    g_file_error_from_errno (errno),
480                    strerror (errno));
481       return (GIOChannel *)NULL;
482     }
483     
484   fid = fileno (f);
485
486   channel = g_io_channel_unix_new (fid);
487   channel->close_on_unref = TRUE;
488   return channel;
489 }
490
491 GIOChannel *
492 g_io_channel_unix_new (gint fd)
493 {
494   GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
495   GIOChannel *channel = (GIOChannel *)unix_channel;
496
497   g_io_channel_init (channel);
498   channel->funcs = &unix_channel_funcs;
499
500   unix_channel->fd = fd;
501   return channel;
502 }
503
504 gint
505 g_io_channel_unix_get_fd (GIOChannel *channel)
506 {
507   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
508   return unix_channel->fd;
509 }