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