1999-07-20 Mark Kettenis <kettenis@gnu.org>
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / sysd-stdio.c
1 /* Copyright (C) 1994, 95, 96, 97, 98 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <hurd.h>
23 #include <fcntl.h>
24 #include <hurd/fd.h>
25
26 extern __io_read_fn __stdio_read;
27 extern __io_write_fn __stdio_write;
28 extern __io_seek_fn __stdio_seek;
29 extern __io_close_fn __stdio_close;
30 extern __io_fileno_fn __stdio_fileno;
31
32
33 /* Check ERR for wanting to generate a signal.  */
34
35 static inline int
36 fd_fail (struct hurd_fd *fd, error_t err)
37 {
38   int signo = _hurd_fd_error_signal (err);
39   if (signo)
40     {
41       const struct hurd_signal_detail detail
42         = { code: __stdio_fileno (fd), error: err, exc: 0 };
43       _hurd_raise_signal (NULL, signo, &detail);
44     }
45   errno = err;
46   return -1;
47 }
48
49
50 /* Read up to N chars into BUF from COOKIE.
51    Return how many chars were read, 0 for EOF or -1 for error.  */
52 ssize_t
53 __stdio_read (cookie, buf, n)
54      void *cookie;
55      char *buf;
56      size_t n;
57 {
58   error_t err;
59   struct hurd_fd *fd = cookie;
60
61   if (! fd)
62     return __hurd_fail (EBADF);
63
64   if (err = _hurd_fd_read (fd, buf, &n, -1))
65     return fd_fail (fd, err);
66
67   return n;
68 }
69
70 /* Write up to N chars from BUF to COOKIE.
71    Return how many chars were written or -1 for error.  */
72 ssize_t
73 __stdio_write (cookie, buf, n)
74      void *cookie;
75      const char *buf;
76      size_t n;
77 {
78   error_t err;
79   size_t wrote, nleft;
80   struct hurd_fd *fd = cookie;
81
82   if (! fd)
83     return __hurd_fail (EBADF);
84
85   nleft = n;
86   do
87     {
88       wrote = nleft;
89       if (err = _hurd_fd_write (fd, buf, &wrote, -1))
90         return fd_fail (fd, err);
91       buf += wrote;
92       nleft -= wrote;
93     } while (nleft > 0);
94
95   return wrote;
96 }
97
98 /* Move COOKIE's file position *POS bytes, according to WHENCE.
99    The current file position is stored in *POS.
100    Returns zero if successful, nonzero if not.  */
101 int
102 __stdio_seek (cookie, pos, whence)
103      void *cookie;
104      fpos_t *pos;
105      int whence;
106 {
107   error_t err;
108   struct hurd_fd *fd = cookie;
109   if (! fd)
110     return __hurd_fail (EBADF);
111   err = HURD_FD_PORT_USE (fd, __io_seek (port, *pos, whence, pos));
112   return err ? fd_fail (fd, err) : 0;
113 }
114
115 /* Close the file associated with COOKIE.
116    Return 0 for success or -1 for failure.  */
117 int
118 __stdio_close (cookie)
119      void *cookie;
120 {
121   error_t error = cookie ? _hurd_fd_close (cookie) : EBADF;
122   return error ? fd_fail (cookie, error) : 0;
123 }
124
125
126 static inline int
127 modeflags (__io_mode m)
128 {
129   int flags = 0;
130   if (m.__read)
131     flags |= O_READ;
132   if (m.__write)
133     flags |= O_WRITE;
134   if (m.__append)
135     flags |= O_APPEND;
136   if (m.__create)
137     flags |= O_CREAT;
138   if (m.__truncate)
139     flags |= O_TRUNC;
140   if (m.__exclusive)
141     flags |= O_EXCL;
142   return flags;
143 }
144
145 /* Open FILENAME with the mode in M.  */
146 int
147 __stdio_open (filename, m, cookieptr)
148      const char *filename;
149      __io_mode m;
150      void **cookieptr;
151 {
152   int flags;
153   file_t port;
154   struct hurd_fd *d;
155
156   flags = modeflags (m);
157   port = __file_name_lookup (filename, flags, 0666 & ~_hurd_umask);
158   if (port == MACH_PORT_NULL)
159     return -1;
160
161   HURD_CRITICAL_BEGIN;
162   d = _hurd_alloc_fd (NULL, 0);
163   if (d != NULL)
164     {
165       _hurd_port2fd (d, port, flags);
166       __spin_unlock (&d->port.lock);
167     }
168   HURD_CRITICAL_END;
169
170   *cookieptr = d;
171   return 0;
172 }
173
174
175 /* Open FILENAME with the mode in M.  Use the same magic cookie
176    already in *COOKIEPTR if possible, closing the old cookie with CLOSEFN.  */
177 int
178 __stdio_reopen (filename, m, cookieptr, closefn)
179      const char *filename;
180      __io_mode m;
181      void **cookieptr;
182      __io_close_fn closefn;
183 {
184   int flags;
185   file_t port;
186   struct hurd_fd *d;
187
188   if (closefn != __stdio_close)
189     {
190       /* The old cookie is Not Of The Body.
191          Just close it and do a normal open.  */
192       (*closefn) (*cookieptr);
193       return __stdio_open (filename, m, cookieptr);
194     }
195
196   /* Open a new port on the file.  */
197   flags = modeflags (m);
198   port = __file_name_lookup (filename, flags, 0666 & ~_hurd_umask);
199
200   /* Install the new port in the same file descriptor slot the old cookie
201      points to.  If opening the file failed, PORT will be MACH_PORT_NULL
202      and installing it in the descriptor will have the effect of closing
203      the old descriptor.  */
204
205   d = *cookieptr;
206   HURD_CRITICAL_BEGIN;
207   __spin_lock (&d->port.lock);
208   _hurd_port2fd (d, port, flags);
209   __spin_unlock (&d->port.lock);
210   HURD_CRITICAL_END;
211
212   return port == MACH_PORT_NULL ? -1 : 0;
213 }
214
215
216 /* Write a message to the error output.
217    Try hard to make it really get out.  */
218 void
219 __stdio_errmsg (msg, len)
220      const char *msg;
221      size_t len;
222 {
223   io_t server;
224   mach_msg_type_number_t wrote;
225
226   server = __getdport (2);
227   __io_write (server, msg, len, -1, &wrote);
228   __mach_port_deallocate (__mach_task_self (), server);
229 }
230
231
232 /* Return the POSIX.1 file descriptor associated with COOKIE,
233    or -1 for errors.  If COOKIE does not relate to any POSIX.1 file
234    descriptor, this should return -1 with errno set to EOPNOTSUPP.  */
235 int
236 __stdio_fileno (cookie)
237      void *cookie;
238 {
239   int fd;
240
241   if (! cookie)
242     return __hurd_fail (EBADF);
243
244   __mutex_lock (&_hurd_dtable_lock);
245   for (fd = 0; fd < _hurd_dtablesize; ++fd)
246     if (_hurd_dtable[fd] == cookie)
247       {
248         __mutex_unlock (&_hurd_dtable_lock);
249         return fd;
250       }
251   __mutex_unlock (&_hurd_dtable_lock);
252
253   /* This should never happen, because this function should not be
254      installed as a stream's __fileno function unless that stream's cookie
255      points to a file descriptor.  */
256   errno = EGRATUITOUS;
257   return -1;
258 }