update from main archive 970118
[kopensolaris-gnu/glibc.git] / sysdeps / generic / sysd-stdio.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27
28 /* Read N bytes into BUF from COOKIE.  */
29 int
30 __stdio_read (cookie, buf, n)
31      void *cookie;
32      register char *buf;
33      register size_t n;
34 {
35   const int fd = (int) cookie;
36 #if     defined (EINTR) && defined (EINTR_REPEAT)
37   int save = errno;
38   int nread;
39
40  try:;
41   __set_errno (0);
42   nread = __read (fd, buf, (int) n);
43   if (nread < 0)
44     {
45       if (errno == EINTR)
46         goto try;
47       return -1;
48     }
49   __set_errno (save);
50   return nread;
51
52 #else   /* No EINTR.  */
53   return __read (fd, buf, n);
54 #endif
55 }
56
57
58 /* Write N bytes from BUF to COOKIE.  */
59 int
60 __stdio_write (cookie, buf, n)
61      void *cookie;
62      register const char *buf;
63      register size_t n;
64 {
65   const int fd = (int) cookie;
66   register size_t written = 0;
67
68   while (n > 0)
69     {
70       int count = __write (fd, buf, (int) n);
71       if (count > 0)
72         {
73           buf += count;
74           written += count;
75           n -= count;
76         }
77       else if (count < 0
78 #if     defined (EINTR) && defined (EINTR_REPEAT)
79                && errno != EINTR
80 #endif
81                )
82         /* Write error.  */
83         return -1;
84     }
85
86   return (int) written;
87 }
88
89
90 /* Move COOKIE's file position *POS bytes, according to WHENCE.
91    The new file position is stored in *POS.
92    Returns zero if successful, nonzero if not.  */
93 int
94 __stdio_seek (cookie, pos, whence)
95      void *cookie;
96      fpos_t *pos;
97      int whence;
98 {
99   off_t new;
100   new = __lseek ((int) cookie, (off_t) *pos, whence);
101   if (new < 0)
102     return 1;
103   *pos = (fpos_t) new;
104   return 0;
105 }
106
107
108 /* Close COOKIE.  */
109 int
110 __stdio_close (cookie)
111      void *cookie;
112 {
113   return __close ((int) cookie);
114 }
115
116 /* Return the POSIX.1 file descriptor associated with COOKIE,
117    or -1 for errors.  If COOKIE does not relate to any POSIX.1 file
118    descriptor, this should return -1 with errno set to EOPNOTSUPP.  */
119 int
120 __stdio_fileno (cookie)
121      void *cookie;
122 {
123   return (int) cookie;
124 }
125
126
127 /* Open the given file with the mode given in the __io_mode argument.  */
128 int
129 __stdio_open (filename, m, cookieptr)
130      const char *filename;
131      __io_mode m;
132      void **cookieptr;
133 {
134   int fd;
135   int mode;
136
137   if (m.__read && m.__write)
138     mode = O_RDWR;
139   else
140     mode = m.__read ? O_RDONLY : O_WRONLY;
141
142   if (m.__append)
143     mode |= O_APPEND;
144   if (m.__exclusive)
145     mode |= O_EXCL;
146   if (m.__truncate)
147     mode |= O_TRUNC;
148
149   if (m.__create)
150     fd = __open (filename, mode | O_CREAT,
151                  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
152   else
153     fd = __open (filename, mode);
154
155   if (fd < 0)
156     return -1;
157
158   *cookieptr = (PTR) fd;
159   return 0;
160 }
161
162
163 /* Open FILENAME with the mode in M.  Use the same magic cookie
164    already in *COOKIEPTR if possible, closing the old cookie with CLOSEFN.  */
165 int
166 __stdio_reopen (filename, m, cookieptr, closefn)
167      const char *filename;
168      __io_mode m;
169      void **cookieptr;
170      __io_close_fn closefn;
171 {
172   void *newcookie;
173
174   /* We leave the old descriptor open while we open the file.
175      That way ``freopen ("/dev/stdin", "r", stdin)'' works.  */
176
177   if (__stdio_open (filename, m, &newcookie))
178     {
179       if (errno == ENFILE || errno == EMFILE)
180         {
181           /* We are out of file descriptors.  Try closing the old one and
182              retrying the open.  */
183           (void) (*closefn) (*cookieptr);
184           if (__stdio_open (filename, m, &newcookie))
185             return -1;
186         }
187       else
188         return -1;
189     }
190
191   if (newcookie != *cookieptr)
192     {
193       if (closefn != __stdio_close ||
194           /* Try to move the descriptor to the desired one.  */
195           __dup2 ((int) newcookie, (int) *cookieptr) < 0)
196         /* Didn't work.  Give the caller the new cookie.  */
197         *cookieptr = newcookie;
198     }
199
200   return 0;
201 }