/* Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include /* Check ERR for wanting to generate a signal. */ int __stdio_fileno (void *); static inline int fd_fail (struct hurd_fd *fd, error_t err) { int signo = _hurd_fd_error_signal (err); if (signo) { const struct hurd_signal_detail detail = { code: __stdio_fileno (fd), error: err, exc: 0 }; _hurd_raise_signal (NULL, signo, &detail); } errno = err; return -1; } /* Read up to N chars into BUF from COOKIE. Return how many chars were read, 0 for EOF or -1 for error. */ ssize_t __stdio_read (cookie, buf, n) void *cookie; char *buf; size_t n; { error_t err; struct hurd_fd *fd = cookie; if (! fd) return __hurd_fail (EBADF); if (err = _hurd_fd_read (fd, buf, &n)) return fd_fail (fd, err); return n; } /* Write up to N chars from BUF to COOKIE. Return how many chars were written or -1 for error. */ ssize_t __stdio_write (cookie, buf, n) void *cookie; const char *buf; size_t n; { error_t err; size_t wrote, nleft; struct hurd_fd *fd = cookie; if (! fd) return __hurd_fail (EBADF); nleft = n; do { wrote = nleft; if (err = _hurd_fd_write (fd, buf, &wrote)) return fd_fail (fd, err); buf += wrote; nleft -= wrote; } while (nleft > 0); return wrote; } /* Move COOKIE's file position *POS bytes, according to WHENCE. The current file position is stored in *POS. Returns zero if successful, nonzero if not. */ int __stdio_seek (cookie, pos, whence) void *cookie; fpos_t *pos; int whence; { error_t err; struct hurd_fd *fd = cookie; if (! fd) return __hurd_fail (EBADF); err = HURD_FD_PORT_USE (fd, __io_seek (port, *pos, whence, pos)); return err ? fd_fail (fd, err) : 0; } /* Close the file associated with COOKIE. Return 0 for success or -1 for failure. */ int __stdio_close (cookie) void *cookie; { error_t error = cookie ? _hurd_fd_close (cookie) : EBADF; return error ? fd_fail (cookie, error) : 0; } static inline int modeflags (__io_mode m) { int flags = 0; if (m.__read) flags |= O_READ; if (m.__write) flags |= O_WRITE; if (m.__append) flags |= O_APPEND; if (m.__create) flags |= O_CREAT; if (m.__truncate) flags |= O_TRUNC; if (m.__exclusive) flags |= O_EXCL; return flags; } /* Open FILENAME with the mode in M. */ int __stdio_open (filename, m, cookieptr) const char *filename; __io_mode m; void **cookieptr; { int flags; file_t port; struct hurd_fd *d; flags = modeflags (m); port = __file_name_lookup (filename, flags, 0666 & ~_hurd_umask); if (port == MACH_PORT_NULL) return -1; HURD_CRITICAL_BEGIN; d = _hurd_alloc_fd (NULL, 0); if (d != NULL) { _hurd_port2fd (d, port, flags); __spin_unlock (&d->port.lock); } HURD_CRITICAL_END; *cookieptr = d; return 0; } /* Open FILENAME with the mode in M. Use the same magic cookie already in *COOKIEPTR if possible, closing the old cookie with CLOSEFN. */ int __stdio_reopen (filename, m, cookieptr) const char *filename; __io_mode m; void **cookieptr; __io_close_fn closefn; { int flags; file_t port; struct hurd_fd *d; if (closefn != __stdio_close) { /* The old cookie is Not Of The Body. Just close it and do a normal open. */ (*closefn) (*cookieptr); return __stdio_open (filename, m, cookieptr); } /* Open a new port on the file. */ flags = modeflags (m); port = __file_name_lookup (filename, flags, 0666 & ~_hurd_umask); /* Install the new port in the same file descriptor slot the old cookie points to. If opening the file failed, PORT will be MACH_PORT_NULL and installing it in the descriptor will have the effect of closing the old descriptor. */ d = *cookieptr; HURD_CRITICAL_BEGIN; __spin_lock (&d->port.lock); _hurd_port2fd (d, port, flags); __spin_unlock (&d->port.lock); HURD_CRITICAL_END; return port == MACH_PORT_NULL ? -1 : 0; } /* Write a message to the error output. Try hard to make it really get out. */ void __stdio_errmsg (msg, len) const char *msg; size_t len; { io_t server; mach_msg_type_number_t wrote; server = __getdport (2); __io_write (server, msg, len, -1, &wrote); __mach_port_deallocate (__mach_task_self (), server); } /* Return the POSIX.1 file descriptor associated with COOKIE, or -1 for errors. If COOKIE does not relate to any POSIX.1 file descriptor, this should return -1 with errno set to EOPNOTSUPP. */ int __stdio_fileno (cookie) void *cookie; { int fd; if (! cookie) return __hurd_fail (EBADF); __mutex_lock (&_hurd_dtable_lock); for (fd = 0; fd < _hurd_dtablesize; ++fd) if (_hurd_dtable[fd] == cookie) { __mutex_unlock (&_hurd_dtable_lock); return fd; } __mutex_unlock (&_hurd_dtable_lock); /* This should never happen, because this function should not be installed as a stream's __fileno function unless that stream's cookie points to a file descriptor. */ errno = EGRATUITOUS; return -1; }