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