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