]>
Commit | Line | Data |
---|---|---|
37233df9 | 1 | /* Copyright (C) 1993-2012 Free Software Foundation, Inc. |
41bdb6e2 | 2 | This file is part of the GNU C Library. |
40a55d20 | 3 | Written by Per Bothner <bothner@cygnus.com>. |
96aa2d94 | 4 | |
41bdb6e2 AJ |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
96aa2d94 | 9 | |
41bdb6e2 AJ |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
40a55d20 | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
41bdb6e2 | 13 | Lesser General Public License for more details. |
96aa2d94 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. | |
96aa2d94 | 18 | |
41bdb6e2 AJ |
19 | As a special exception, if you link the code in this file with |
20 | files compiled with a GNU compiler to produce an executable, | |
21 | that does not cause the resulting executable to be covered by | |
22 | the GNU Lesser General Public License. This exception does not | |
23 | however invalidate any other reasons why the executable file | |
24 | might be covered by the GNU Lesser General Public License. | |
25 | This exception applies to code released by its copyright holders | |
26 | in files containing the exception. */ | |
96aa2d94 | 27 | |
96aa2d94 | 28 | |
fa0bc87c RM |
29 | #ifndef _POSIX_SOURCE |
30 | # define _POSIX_SOURCE | |
31 | #endif | |
96aa2d94 | 32 | #include "libioP.h" |
129d706d | 33 | #include <assert.h> |
96aa2d94 | 34 | #include <fcntl.h> |
284749da | 35 | #include <sys/param.h> |
96aa2d94 RM |
36 | #include <sys/types.h> |
37 | #include <sys/stat.h> | |
38 | #include <string.h> | |
39 | #include <errno.h> | |
c9f10034 | 40 | #include <unistd.h> |
00bc5db0 | 41 | #include <stdlib.h> |
4e2e9999 UD |
42 | #if _LIBC |
43 | # include "../wcsmbs/wcsmbsload.h" | |
129d706d UD |
44 | # include "../iconv/gconv_charset.h" |
45 | # include "../iconv/gconv_int.h" | |
0bf98029 | 46 | # include <shlib-compat.h> |
73299943 | 47 | # include <not-cancel.h> |
37233df9 | 48 | # include <kernel-features.h> |
4e2e9999 | 49 | #endif |
96aa2d94 RM |
50 | #ifndef errno |
51 | extern int errno; | |
52 | #endif | |
4547c1a4 UD |
53 | #ifndef __set_errno |
54 | # define __set_errno(Val) errno = (Val) | |
55 | #endif | |
96aa2d94 | 56 | |
68dbb3a6 UD |
57 | |
58 | #ifdef _LIBC | |
61eb22d3 | 59 | # define open(Name, Flags, Prot) __open (Name, Flags, Prot) |
61eb22d3 UD |
60 | # define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence) |
61 | # define read(FD, Buf, NBytes) __read (FD, Buf, NBytes) | |
62 | # define write(FD, Buf, NBytes) __write (FD, Buf, NBytes) | |
319d719d UD |
63 | #else |
64 | # define _IO_new_do_write _IO_do_write | |
65 | # define _IO_new_file_attach _IO_file_attach | |
66 | # define _IO_new_file_close_it _IO_file_close_it | |
67 | # define _IO_new_file_finish _IO_file_finish | |
68 | # define _IO_new_file_fopen _IO_file_fopen | |
69 | # define _IO_new_file_init _IO_file_init | |
70 | # define _IO_new_file_setbuf _IO_file_setbuf | |
71 | # define _IO_new_file_sync _IO_file_sync | |
72 | # define _IO_new_file_overflow _IO_file_overflow | |
73 | # define _IO_new_file_seekoff _IO_file_seekoff | |
74 | # define _IO_new_file_underflow _IO_file_underflow | |
75 | # define _IO_new_file_write _IO_file_write | |
76 | # define _IO_new_file_xsputn _IO_file_xsputn | |
68dbb3a6 UD |
77 | #endif |
78 | ||
129d706d UD |
79 | |
80 | #ifdef _LIBC | |
ab26a24a | 81 | extern struct __gconv_trans_data __libio_translit attribute_hidden; |
129d706d UD |
82 | #endif |
83 | ||
84 | ||
96aa2d94 RM |
85 | /* An fstream can be in at most one of put mode, get mode, or putback mode. |
86 | Putback mode is a variant of get mode. | |
87 | ||
88 | In a filebuf, there is only one current position, instead of two | |
6d52618b | 89 | separate get and put pointers. In get mode, the current position |
96aa2d94 RM |
90 | is that of gptr(); in put mode that of pptr(). |
91 | ||
92 | The position in the buffer that corresponds to the position | |
a18f587d UD |
93 | in external file system is normally _IO_read_end, except in putback |
94 | mode, when it is _IO_save_end. | |
96aa2d94 RM |
95 | If the field _fb._offset is >= 0, it gives the offset in |
96 | the file as a whole corresponding to eGptr(). (?) | |
97 | ||
98 | PUT MODE: | |
a18f587d UD |
99 | If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end, |
100 | and _IO_read_base are equal to each other. These are usually equal | |
101 | to _IO_buf_base, though not necessarily if we have switched from | |
102 | get mode to put mode. (The reason is to maintain the invariant | |
103 | that _IO_read_end corresponds to the external file position.) | |
1ffb8c90 | 104 | _IO_write_base is non-NULL and usually equal to _IO_buf_base. |
a18f587d UD |
105 | We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode. |
106 | The un-flushed character are those between _IO_write_base and _IO_write_ptr. | |
107 | ||
96aa2d94 RM |
108 | GET MODE: |
109 | If a filebuf is in get or putback mode, eback() != egptr(). | |
110 | In get mode, the unread characters are between gptr() and egptr(). | |
111 | The OS file position corresponds to that of egptr(). | |
a18f587d | 112 | |
96aa2d94 RM |
113 | PUTBACK MODE: |
114 | Putback mode is used to remember "excess" characters that have | |
115 | been sputbackc'd in a separate putback buffer. | |
116 | In putback mode, the get buffer points to the special putback buffer. | |
117 | The unread characters are the characters between gptr() and egptr() | |
118 | in the putback buffer, as well as the area between save_gptr() | |
119 | and save_egptr(), which point into the original reserve buffer. | |
120 | (The pointers save_gptr() and save_egptr() are the values | |
121 | of gptr() and egptr() at the time putback mode was entered.) | |
122 | The OS position corresponds to that of save_egptr(). | |
23396375 | 123 | |
96aa2d94 | 124 | LINE BUFFERED OUTPUT: |
a18f587d | 125 | During line buffered output, _IO_write_base==base() && epptr()==base(). |
96aa2d94 RM |
126 | However, ptr() may be anywhere between base() and ebuf(). |
127 | This forces a call to filebuf::overflow(int C) on every put. | |
128 | If there is more space in the buffer, and C is not a '\n', | |
129 | then C is inserted, and pptr() incremented. | |
23396375 | 130 | |
96aa2d94 RM |
131 | UNBUFFERED STREAMS: |
132 | If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer. | |
133 | */ | |
134 | ||
135 | #define CLOSED_FILEBUF_FLAGS \ | |
136 | (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET) | |
137 | ||
138 | ||
139 | void | |
b259e746 | 140 | _IO_new_file_init (fp) |
2ca8b1ee | 141 | struct _IO_FILE_plus *fp; |
96aa2d94 RM |
142 | { |
143 | /* POSIX.1 allows another file handle to be used to change the position | |
144 | of our file descriptor. Hence we actually don't know the actual | |
145 | position before we do the first fseek (and until a following fflush). */ | |
2ca8b1ee GM |
146 | fp->file._offset = _IO_pos_BAD; |
147 | fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS; | |
96aa2d94 | 148 | |
d18ea0c5 | 149 | _IO_link_in (fp); |
2ca8b1ee | 150 | fp->file._fileno = -1; |
96aa2d94 | 151 | } |
d18ea0c5 | 152 | libc_hidden_ver (_IO_new_file_init, _IO_file_init) |
96aa2d94 RM |
153 | |
154 | int | |
b259e746 | 155 | _IO_new_file_close_it (fp) |
40a55d20 | 156 | _IO_FILE *fp; |
96aa2d94 | 157 | { |
40a55d20 | 158 | if (!_IO_file_is_open (fp)) |
96aa2d94 RM |
159 | return EOF; |
160 | ||
fcabc0f8 UD |
161 | int write_status; |
162 | if (_IO_in_put_mode (fp)) | |
3384a8d6 | 163 | write_status = _IO_do_flush (fp); |
fcabc0f8 UD |
164 | else if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL |
165 | && !_IO_in_backup (fp)) | |
166 | { | |
167 | off64_t o = _IO_SEEKOFF (fp, 0, _IO_seek_cur, 0); | |
168 | if (o == WEOF) | |
169 | write_status = EOF; | |
170 | else | |
171 | write_status = _IO_SYSSEEK (fp, o, SEEK_SET) < 0 ? EOF : 0; | |
172 | } | |
ca408c15 UD |
173 | else |
174 | write_status = 0; | |
96aa2d94 | 175 | |
d18ea0c5 | 176 | _IO_unsave_markers (fp); |
96aa2d94 | 177 | |
94b7cc37 UD |
178 | int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0 |
179 | ? _IO_SYSCLOSE (fp) : 0); | |
96aa2d94 RM |
180 | |
181 | /* Free buffer. */ | |
319d719d | 182 | #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T |
1e88bd0f | 183 | if (fp->_mode > 0) |
d64b6ad0 | 184 | { |
44c4ccbc | 185 | if (_IO_have_wbackup (fp)) |
d18ea0c5 AS |
186 | _IO_free_wbackup_area (fp); |
187 | _IO_wsetb (fp, NULL, NULL, 0); | |
d64b6ad0 UD |
188 | _IO_wsetg (fp, NULL, NULL, NULL); |
189 | _IO_wsetp (fp, NULL, NULL); | |
190 | } | |
319d719d | 191 | #endif |
d18ea0c5 | 192 | _IO_setb (fp, NULL, NULL, 0); |
1e88bd0f UD |
193 | _IO_setg (fp, NULL, NULL, NULL); |
194 | _IO_setp (fp, NULL, NULL); | |
96aa2d94 | 195 | |
d18ea0c5 | 196 | _IO_un_link ((struct _IO_FILE_plus *) fp); |
96aa2d94 | 197 | fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS; |
110215a9 | 198 | fp->_fileno = -1; |
bd355af0 | 199 | fp->_offset = _IO_pos_BAD; |
96aa2d94 | 200 | |
fa0bc87c | 201 | return close_status ? close_status : write_status; |
96aa2d94 | 202 | } |
d18ea0c5 | 203 | libc_hidden_ver (_IO_new_file_close_it, _IO_file_close_it) |
96aa2d94 RM |
204 | |
205 | void | |
b259e746 | 206 | _IO_new_file_finish (fp, dummy) |
40a55d20 UD |
207 | _IO_FILE *fp; |
208 | int dummy; | |
96aa2d94 | 209 | { |
40a55d20 | 210 | if (_IO_file_is_open (fp)) |
96aa2d94 RM |
211 | { |
212 | _IO_do_flush (fp); | |
213 | if (!(fp->_flags & _IO_DELETE_DONT_CLOSE)) | |
214 | _IO_SYSCLOSE (fp); | |
215 | } | |
d18ea0c5 | 216 | _IO_default_finish (fp, 0); |
96aa2d94 | 217 | } |
d18ea0c5 | 218 | libc_hidden_ver (_IO_new_file_finish, _IO_file_finish) |
96aa2d94 | 219 | |
bd355af0 UD |
220 | _IO_FILE * |
221 | _IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64) | |
222 | _IO_FILE *fp; | |
223 | const char *filename; | |
224 | int posix_mode; | |
225 | int prot; | |
226 | int read_write; | |
227 | int is32not64; | |
228 | { | |
229 | int fdesc; | |
ee8449f7 | 230 | #ifdef _LIBC |
e3c54d80 | 231 | if (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0)) |
ee8449f7 UD |
232 | fdesc = open_not_cancel (filename, |
233 | posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot); | |
234 | else | |
235 | fdesc = open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot); | |
bd355af0 UD |
236 | #else |
237 | fdesc = open (filename, posix_mode, prot); | |
238 | #endif | |
239 | if (fdesc < 0) | |
240 | return NULL; | |
241 | fp->_fileno = fdesc; | |
242 | _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); | |
c096ab25 | 243 | if ((read_write & _IO_IS_APPENDING) && (read_write & _IO_NO_READS)) |
bd355af0 UD |
244 | if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT) |
245 | == _IO_pos_BAD && errno != ESPIPE) | |
2c617417 | 246 | { |
e3c54d80 | 247 | close_not_cancel (fdesc); |
2c617417 UD |
248 | return NULL; |
249 | } | |
d18ea0c5 | 250 | _IO_link_in ((struct _IO_FILE_plus *) fp); |
bd355af0 UD |
251 | return fp; |
252 | } | |
ee2a5ae8 | 253 | libc_hidden_def (_IO_file_open) |
bd355af0 | 254 | |
96aa2d94 | 255 | _IO_FILE * |
b259e746 | 256 | _IO_new_file_fopen (fp, filename, mode, is32not64) |
40a55d20 UD |
257 | _IO_FILE *fp; |
258 | const char *filename; | |
259 | const char *mode; | |
dfd2257a | 260 | int is32not64; |
96aa2d94 RM |
261 | { |
262 | int oflags = 0, omode; | |
bd355af0 | 263 | int read_write; |
96aa2d94 | 264 | int oprot = 0666; |
f38931a9 | 265 | int i; |
4e2e9999 | 266 | _IO_FILE *result; |
129d706d | 267 | #ifdef _LIBC |
4e2e9999 | 268 | const char *cs; |
129d706d | 269 | const char *last_recognized; |
4e2e9999 UD |
270 | #endif |
271 | ||
96aa2d94 RM |
272 | if (_IO_file_is_open (fp)) |
273 | return 0; | |
f38931a9 | 274 | switch (*mode) |
40a55d20 UD |
275 | { |
276 | case 'r': | |
277 | omode = O_RDONLY; | |
278 | read_write = _IO_NO_WRITES; | |
279 | break; | |
280 | case 'w': | |
281 | omode = O_WRONLY; | |
282 | oflags = O_CREAT|O_TRUNC; | |
283 | read_write = _IO_NO_READS; | |
284 | break; | |
285 | case 'a': | |
286 | omode = O_WRONLY; | |
287 | oflags = O_CREAT|O_APPEND; | |
288 | read_write = _IO_NO_READS|_IO_IS_APPENDING; | |
289 | break; | |
290 | default: | |
291 | __set_errno (EINVAL); | |
292 | return NULL; | |
293 | } | |
129d706d UD |
294 | #ifdef _LIBC |
295 | last_recognized = mode; | |
296 | #endif | |
b722481a | 297 | for (i = 1; i < 7; ++i) |
40a55d20 | 298 | { |
f38931a9 UD |
299 | switch (*++mode) |
300 | { | |
301 | case '\0': | |
302 | break; | |
303 | case '+': | |
304 | omode = O_RDWR; | |
305 | read_write &= _IO_IS_APPENDING; | |
129d706d UD |
306 | #ifdef _LIBC |
307 | last_recognized = mode; | |
308 | #endif | |
f38931a9 UD |
309 | continue; |
310 | case 'x': | |
311 | oflags |= O_EXCL; | |
129d706d UD |
312 | #ifdef _LIBC |
313 | last_recognized = mode; | |
314 | #endif | |
f38931a9 UD |
315 | continue; |
316 | case 'b': | |
129d706d UD |
317 | #ifdef _LIBC |
318 | last_recognized = mode; | |
319 | #endif | |
b7fc6d07 UD |
320 | continue; |
321 | case 'm': | |
322 | fp->_flags2 |= _IO_FLAGS2_MMAP; | |
323 | continue; | |
ee8449f7 UD |
324 | case 'c': |
325 | fp->_flags2 |= _IO_FLAGS2_NOTCANCEL; | |
0d74e043 | 326 | continue; |
65d834b0 | 327 | case 'e': |
94b7cc37 | 328 | #ifdef O_CLOEXEC |
65d834b0 | 329 | oflags |= O_CLOEXEC; |
65d834b0 | 330 | #endif |
94b7cc37 UD |
331 | fp->_flags2 |= _IO_FLAGS2_CLOEXEC; |
332 | continue; | |
f38931a9 UD |
333 | default: |
334 | /* Ignore. */ | |
335 | continue; | |
336 | } | |
337 | break; | |
40a55d20 | 338 | } |
f38931a9 | 339 | |
4e2e9999 UD |
340 | result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write, |
341 | is32not64); | |
342 | ||
a101b025 | 343 | if (result != NULL) |
94b7cc37 | 344 | { |
a101b025 AJ |
345 | #ifndef __ASSUME_O_CLOEXEC |
346 | if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0) | |
94b7cc37 | 347 | { |
a101b025 AJ |
348 | int fd = _IO_fileno (fp); |
349 | if (__have_o_cloexec == 0) | |
350 | { | |
351 | int flags = __fcntl (fd, F_GETFD); | |
352 | __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1; | |
353 | } | |
354 | if (__have_o_cloexec < 0) | |
355 | __fcntl (fd, F_SETFD, FD_CLOEXEC); | |
94b7cc37 | 356 | } |
94b7cc37 | 357 | #endif |
4e2e9999 | 358 | |
129d706d UD |
359 | /* Test whether the mode string specifies the conversion. */ |
360 | cs = strstr (last_recognized + 1, ",ccs="); | |
361 | if (cs != NULL) | |
362 | { | |
363 | /* Yep. Load the appropriate conversions and set the orientation | |
364 | to wide. */ | |
365 | struct gconv_fcts fcts; | |
366 | struct _IO_codecvt *cc; | |
367 | char *endp = __strchrnul (cs + 5, ','); | |
368 | char ccs[endp - (cs + 5) + 3]; | |
369 | ||
370 | *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0'; | |
371 | strip (ccs, ccs); | |
372 | ||
373 | if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0' | |
374 | ? upstr (ccs, cs + 5) : ccs) != 0) | |
375 | { | |
376 | /* Something went wrong, we cannot load the conversion modules. | |
377 | This means we cannot proceed since the user explicitly asked | |
378 | for these. */ | |
d18ea0c5 | 379 | (void) _IO_file_close_it (fp); |
129d706d UD |
380 | __set_errno (EINVAL); |
381 | return NULL; | |
382 | } | |
383 | ||
384 | assert (fcts.towc_nsteps == 1); | |
385 | assert (fcts.tomb_nsteps == 1); | |
386 | ||
387 | fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end; | |
388 | fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base; | |
389 | ||
390 | /* Clear the state. We start all over again. */ | |
391 | memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t)); | |
392 | memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t)); | |
393 | ||
394 | cc = fp->_codecvt = &fp->_wide_data->_codecvt; | |
395 | ||
396 | /* The functions are always the same. */ | |
397 | *cc = __libio_codecvt; | |
398 | ||
399 | cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; | |
400 | cc->__cd_in.__cd.__steps = fcts.towc; | |
401 | ||
402 | cc->__cd_in.__cd.__data[0].__invocation_counter = 0; | |
403 | cc->__cd_in.__cd.__data[0].__internal_use = 1; | |
404 | cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST; | |
405 | cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state; | |
406 | ||
407 | /* XXX For now no transliteration. */ | |
408 | cc->__cd_in.__cd.__data[0].__trans = NULL; | |
409 | ||
410 | cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps; | |
411 | cc->__cd_out.__cd.__steps = fcts.tomb; | |
412 | ||
413 | cc->__cd_out.__cd.__data[0].__invocation_counter = 0; | |
414 | cc->__cd_out.__cd.__data[0].__internal_use = 1; | |
415 | cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST; | |
416 | cc->__cd_out.__cd.__data[0].__statep = | |
417 | &result->_wide_data->_IO_state; | |
418 | ||
419 | /* And now the transliteration. */ | |
420 | cc->__cd_out.__cd.__data[0].__trans = &__libio_translit; | |
421 | ||
a815c3ab UD |
422 | /* From now on use the wide character callback functions. */ |
423 | ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable; | |
424 | ||
129d706d UD |
425 | /* Set the mode now. */ |
426 | result->_mode = 1; | |
129d706d | 427 | } |
4e2e9999 | 428 | } |
4e2e9999 UD |
429 | |
430 | return result; | |
96aa2d94 | 431 | } |
d18ea0c5 | 432 | libc_hidden_ver (_IO_new_file_fopen, _IO_file_fopen) |
96aa2d94 | 433 | |
40a55d20 | 434 | _IO_FILE * |
b259e746 | 435 | _IO_new_file_attach (fp, fd) |
40a55d20 UD |
436 | _IO_FILE *fp; |
437 | int fd; | |
96aa2d94 | 438 | { |
40a55d20 | 439 | if (_IO_file_is_open (fp)) |
96aa2d94 RM |
440 | return NULL; |
441 | fp->_fileno = fd; | |
442 | fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES); | |
443 | fp->_flags |= _IO_DELETE_DONT_CLOSE; | |
f65fd747 UD |
444 | /* Get the current position of the file. */ |
445 | /* We have to do that since that may be junk. */ | |
bd355af0 | 446 | fp->_offset = _IO_pos_BAD; |
c4a710b6 | 447 | int save_errno = errno; |
dfd2257a | 448 | if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT) |
f65fd747 UD |
449 | == _IO_pos_BAD && errno != ESPIPE) |
450 | return NULL; | |
11ed3eae | 451 | __set_errno (save_errno); |
96aa2d94 RM |
452 | return fp; |
453 | } | |
d18ea0c5 | 454 | libc_hidden_ver (_IO_new_file_attach, _IO_file_attach) |
96aa2d94 | 455 | |
40a55d20 | 456 | _IO_FILE * |
b259e746 | 457 | _IO_new_file_setbuf (fp, p, len) |
40a55d20 UD |
458 | _IO_FILE *fp; |
459 | char *p; | |
460 | _IO_ssize_t len; | |
96aa2d94 | 461 | { |
d64b6ad0 UD |
462 | if (_IO_default_setbuf (fp, p, len) == NULL) |
463 | return NULL; | |
96aa2d94 | 464 | |
d64b6ad0 UD |
465 | fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end |
466 | = fp->_IO_buf_base; | |
467 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); | |
96aa2d94 | 468 | |
d64b6ad0 | 469 | return fp; |
96aa2d94 | 470 | } |
d18ea0c5 | 471 | libc_hidden_ver (_IO_new_file_setbuf, _IO_file_setbuf) |
96aa2d94 | 472 | |
bff334e0 UD |
473 | |
474 | _IO_FILE * | |
475 | _IO_file_setbuf_mmap (fp, p, len) | |
476 | _IO_FILE *fp; | |
477 | char *p; | |
478 | _IO_ssize_t len; | |
479 | { | |
480 | _IO_FILE *result; | |
481 | ||
482 | /* Change the function table. */ | |
15a686af | 483 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps; |
bff334e0 UD |
484 | fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; |
485 | ||
486 | /* And perform the normal operation. */ | |
487 | result = _IO_new_file_setbuf (fp, p, len); | |
488 | ||
489 | /* If the call failed, restore to using mmap. */ | |
490 | if (result == NULL) | |
491 | { | |
492 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps_mmap; | |
493 | fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap; | |
494 | } | |
495 | ||
496 | return result; | |
497 | } | |
498 | ||
0fca3153 | 499 | static _IO_size_t new_do_write (_IO_FILE *, const char *, _IO_size_t); |
0720f75c | 500 | |
96aa2d94 | 501 | /* Write TO_DO bytes from DATA to FP. |
68dbb3a6 | 502 | Then mark FP as having empty buffers. */ |
96aa2d94 RM |
503 | |
504 | int | |
b259e746 | 505 | _IO_new_do_write (fp, data, to_do) |
40a55d20 UD |
506 | _IO_FILE *fp; |
507 | const char *data; | |
508 | _IO_size_t to_do; | |
0720f75c | 509 | { |
6dd67bd5 UD |
510 | return (to_do == 0 |
511 | || (_IO_size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF; | |
0720f75c | 512 | } |
d18ea0c5 | 513 | libc_hidden_ver (_IO_new_do_write, _IO_do_write) |
0720f75c UD |
514 | |
515 | static | |
ccf3ea43 | 516 | _IO_size_t |
0720f75c UD |
517 | new_do_write (fp, data, to_do) |
518 | _IO_FILE *fp; | |
519 | const char *data; | |
520 | _IO_size_t to_do; | |
96aa2d94 RM |
521 | { |
522 | _IO_size_t count; | |
96aa2d94 RM |
523 | if (fp->_flags & _IO_IS_APPENDING) |
524 | /* On a system without a proper O_APPEND implementation, | |
525 | you would need to sys_seek(0, SEEK_END) here, but is | |
ded5b9b7 | 526 | not needed nor desirable for Unix- or Posix-like systems. |
96aa2d94 RM |
527 | Instead, just indicate that offset (before and after) is |
528 | unpredictable. */ | |
bd355af0 | 529 | fp->_offset = _IO_pos_BAD; |
96aa2d94 | 530 | else if (fp->_IO_read_end != fp->_IO_write_base) |
23396375 | 531 | { |
d64b6ad0 | 532 | _IO_off64_t new_pos |
40a55d20 | 533 | = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1); |
96aa2d94 | 534 | if (new_pos == _IO_pos_BAD) |
0720f75c | 535 | return 0; |
bd355af0 | 536 | fp->_offset = new_pos; |
96aa2d94 RM |
537 | } |
538 | count = _IO_SYSWRITE (fp, data, to_do); | |
0720f75c | 539 | if (fp->_cur_column && count) |
d18ea0c5 | 540 | fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1; |
40a55d20 | 541 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); |
96aa2d94 | 542 | fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base; |
076bfcf6 | 543 | fp->_IO_write_end = (fp->_mode <= 0 |
d64b6ad0 | 544 | && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) |
40a55d20 | 545 | ? fp->_IO_buf_base : fp->_IO_buf_end); |
0720f75c | 546 | return count; |
96aa2d94 RM |
547 | } |
548 | ||
549 | int | |
b259e746 | 550 | _IO_new_file_underflow (fp) |
40a55d20 | 551 | _IO_FILE *fp; |
96aa2d94 RM |
552 | { |
553 | _IO_ssize_t count; | |
554 | #if 0 | |
555 | /* SysV does not make this test; take it out for compatibility */ | |
556 | if (fp->_flags & _IO_EOF_SEEN) | |
557 | return (EOF); | |
558 | #endif | |
559 | ||
560 | if (fp->_flags & _IO_NO_READS) | |
feb3c934 | 561 | { |
58034572 | 562 | fp->_flags |= _IO_ERR_SEEN; |
feb3c934 UD |
563 | __set_errno (EBADF); |
564 | return EOF; | |
565 | } | |
96aa2d94 | 566 | if (fp->_IO_read_ptr < fp->_IO_read_end) |
40a55d20 | 567 | return *(unsigned char *) fp->_IO_read_ptr; |
96aa2d94 RM |
568 | |
569 | if (fp->_IO_buf_base == NULL) | |
00bc5db0 UD |
570 | { |
571 | /* Maybe we already have a push back pointer. */ | |
572 | if (fp->_IO_save_base != NULL) | |
573 | { | |
574 | free (fp->_IO_save_base); | |
575 | fp->_flags &= ~_IO_IN_BACKUP; | |
576 | } | |
d18ea0c5 | 577 | _IO_doallocbuf (fp); |
00bc5db0 | 578 | } |
96aa2d94 RM |
579 | |
580 | /* Flush all line buffered files before reading. */ | |
581 | /* FIXME This can/should be moved to genops ?? */ | |
582 | if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) | |
3d759cb8 UD |
583 | { |
584 | #if 0 | |
d18ea0c5 | 585 | _IO_flush_all_linebuffered (); |
3d759cb8 UD |
586 | #else |
587 | /* We used to flush all line-buffered stream. This really isn't | |
588 | required by any standard. My recollection is that | |
589 | traditional Unix systems did this for stdout. stderr better | |
590 | not be line buffered. So we do just that here | |
591 | explicitly. --drepper */ | |
0261d33f | 592 | _IO_acquire_lock (_IO_stdout); |
3d759cb8 UD |
593 | |
594 | if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF)) | |
595 | == (_IO_LINKED | _IO_LINE_BUF)) | |
596 | _IO_OVERFLOW (_IO_stdout, EOF); | |
597 | ||
0261d33f | 598 | _IO_release_lock (_IO_stdout); |
3d759cb8 UD |
599 | #endif |
600 | } | |
96aa2d94 | 601 | |
d18ea0c5 | 602 | _IO_switch_to_get_mode (fp); |
96aa2d94 | 603 | |
2d7da676 UD |
604 | /* This is very tricky. We have to adjust those |
605 | pointers before we call _IO_SYSREAD () since | |
606 | we may longjump () out while waiting for | |
607 | input. Those pointers may be screwed up. H.J. */ | |
608 | fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; | |
609 | fp->_IO_read_end = fp->_IO_buf_base; | |
610 | fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end | |
611 | = fp->_IO_buf_base; | |
612 | ||
96aa2d94 RM |
613 | count = _IO_SYSREAD (fp, fp->_IO_buf_base, |
614 | fp->_IO_buf_end - fp->_IO_buf_base); | |
615 | if (count <= 0) | |
616 | { | |
617 | if (count == 0) | |
618 | fp->_flags |= _IO_EOF_SEEN; | |
619 | else | |
620 | fp->_flags |= _IO_ERR_SEEN, count = 0; | |
621 | } | |
2d7da676 | 622 | fp->_IO_read_end += count; |
96aa2d94 RM |
623 | if (count == 0) |
624 | return EOF; | |
bd355af0 UD |
625 | if (fp->_offset != _IO_pos_BAD) |
626 | _IO_pos_adjust (fp->_offset, count); | |
40a55d20 | 627 | return *(unsigned char *) fp->_IO_read_ptr; |
96aa2d94 | 628 | } |
d18ea0c5 | 629 | libc_hidden_ver (_IO_new_file_underflow, _IO_file_underflow) |
96aa2d94 | 630 | |
acbee5f6 RM |
631 | /* Guts of underflow callback if we mmap the file. This stats the file and |
632 | updates the stream state to match. In the normal case we return zero. | |
633 | If the file is no longer eligible for mmap, its jump tables are reset to | |
634 | the vanilla ones and we return nonzero. */ | |
635 | static int | |
636 | mmap_remap_check (_IO_FILE *fp) | |
0469311e | 637 | { |
acbee5f6 RM |
638 | struct _G_stat64 st; |
639 | ||
640 | if (_IO_SYSSTAT (fp, &st) == 0 | |
641 | && S_ISREG (st.st_mode) && st.st_size != 0 | |
642 | /* Limit the file size to 1MB for 32-bit machines. */ | |
643 | && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024)) | |
0469311e | 644 | { |
acbee5f6 RM |
645 | const size_t pagesize = __getpagesize (); |
646 | # define ROUNDED(x) (((x) + pagesize - 1) & ~(pagesize - 1)) | |
647 | if (ROUNDED (st.st_size) < ROUNDED (fp->_IO_buf_end | |
648 | - fp->_IO_buf_base)) | |
649 | { | |
650 | /* We can trim off some pages past the end of the file. */ | |
651 | (void) __munmap (fp->_IO_buf_base + ROUNDED (st.st_size), | |
652 | ROUNDED (fp->_IO_buf_end - fp->_IO_buf_base) | |
653 | - ROUNDED (st.st_size)); | |
654 | fp->_IO_buf_end = fp->_IO_buf_base + st.st_size; | |
655 | } | |
656 | else if (ROUNDED (st.st_size) > ROUNDED (fp->_IO_buf_end | |
657 | - fp->_IO_buf_base)) | |
658 | { | |
659 | /* The file added some pages. We need to remap it. */ | |
660 | void *p; | |
eaae7493 | 661 | #ifdef _G_HAVE_MREMAP |
acbee5f6 RM |
662 | p = __mremap (fp->_IO_buf_base, ROUNDED (fp->_IO_buf_end |
663 | - fp->_IO_buf_base), | |
664 | ROUNDED (st.st_size), MREMAP_MAYMOVE); | |
665 | if (p == MAP_FAILED) | |
666 | { | |
667 | (void) __munmap (fp->_IO_buf_base, | |
668 | fp->_IO_buf_end - fp->_IO_buf_base); | |
669 | goto punt; | |
670 | } | |
671 | #else | |
672 | (void) __munmap (fp->_IO_buf_base, | |
673 | fp->_IO_buf_end - fp->_IO_buf_base); | |
674 | # ifdef _G_MMAP64 | |
675 | p = _G_MMAP64 (NULL, st.st_size, PROT_READ, MAP_SHARED, | |
676 | fp->_fileno, 0); | |
677 | # else | |
678 | p = __mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, | |
679 | fp->_fileno, 0); | |
680 | # endif | |
681 | if (p == MAP_FAILED) | |
682 | goto punt; | |
683 | #endif | |
684 | fp->_IO_buf_base = p; | |
685 | fp->_IO_buf_end = fp->_IO_buf_base + st.st_size; | |
686 | } | |
687 | else | |
688 | { | |
689 | /* The number of pages didn't change. */ | |
690 | fp->_IO_buf_end = fp->_IO_buf_base + st.st_size; | |
691 | } | |
692 | # undef ROUNDED | |
693 | ||
694 | fp->_offset -= fp->_IO_read_end - fp->_IO_read_ptr; | |
fc77d66a RM |
695 | _IO_setg (fp, fp->_IO_buf_base, |
696 | fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base | |
697 | ? fp->_IO_buf_base + fp->_offset : fp->_IO_buf_end, | |
acbee5f6 | 698 | fp->_IO_buf_end); |
c4292489 | 699 | |
fc77d66a RM |
700 | /* If we are already positioned at or past the end of the file, don't |
701 | change the current offset. If not, seek past what we have mapped, | |
702 | mimicking the position left by a normal underflow reading into its | |
703 | buffer until EOF. */ | |
704 | ||
705 | if (fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base) | |
706 | { | |
707 | if ( | |
0469311e | 708 | # ifdef _G_LSEEK64 |
fc77d66a | 709 | _G_LSEEK64 |
0469311e | 710 | # else |
fc77d66a | 711 | __lseek |
0469311e | 712 | # endif |
fc77d66a RM |
713 | (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET) |
714 | != fp->_IO_buf_end - fp->_IO_buf_base) | |
715 | fp->_flags |= _IO_ERR_SEEN; | |
716 | else | |
717 | fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base; | |
0469311e | 718 | } |
acbee5f6 RM |
719 | |
720 | return 0; | |
721 | } | |
722 | else | |
723 | { | |
724 | /* Life is no longer good for mmap. Punt it. */ | |
725 | (void) __munmap (fp->_IO_buf_base, | |
726 | fp->_IO_buf_end - fp->_IO_buf_base); | |
727 | punt: | |
728 | fp->_IO_buf_base = fp->_IO_buf_end = NULL; | |
729 | _IO_setg (fp, NULL, NULL, NULL); | |
730 | if (fp->_mode <= 0) | |
15a686af | 731 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps; |
acbee5f6 RM |
732 | else |
733 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_wfile_jumps; | |
734 | fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; | |
735 | ||
736 | return 1; | |
0469311e | 737 | } |
acbee5f6 RM |
738 | } |
739 | ||
740 | /* Special callback replacing the underflow callbacks if we mmap the file. */ | |
741 | int | |
742 | _IO_file_underflow_mmap (_IO_FILE *fp) | |
743 | { | |
744 | if (fp->_IO_read_ptr < fp->_IO_read_end) | |
745 | return *(unsigned char *) fp->_IO_read_ptr; | |
746 | ||
747 | if (__builtin_expect (mmap_remap_check (fp), 0)) | |
748 | /* We punted to the regular file functions. */ | |
749 | return _IO_UNDERFLOW (fp); | |
750 | ||
751 | if (fp->_IO_read_ptr < fp->_IO_read_end) | |
752 | return *(unsigned char *) fp->_IO_read_ptr; | |
0469311e UD |
753 | |
754 | fp->_flags |= _IO_EOF_SEEN; | |
755 | return EOF; | |
756 | } | |
757 | ||
acbee5f6 RM |
758 | static void |
759 | decide_maybe_mmap (_IO_FILE *fp) | |
760 | { | |
761 | /* We use the file in read-only mode. This could mean we can | |
762 | mmap the file and use it without any copying. But not all | |
763 | file descriptors are for mmap-able objects and on 32-bit | |
764 | machines we don't want to map files which are too large since | |
765 | this would require too much virtual memory. */ | |
766 | struct _G_stat64 st; | |
767 | ||
768 | if (_IO_SYSSTAT (fp, &st) == 0 | |
769 | && S_ISREG (st.st_mode) && st.st_size != 0 | |
770 | /* Limit the file size to 1MB for 32-bit machines. */ | |
771 | && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024) | |
772 | /* Sanity check. */ | |
773 | && (fp->_offset == _IO_pos_BAD || fp->_offset <= st.st_size)) | |
774 | { | |
775 | /* Try to map the file. */ | |
776 | void *p; | |
777 | ||
778 | # ifdef _G_MMAP64 | |
779 | p = _G_MMAP64 (NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0); | |
780 | # else | |
781 | p = __mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0); | |
782 | # endif | |
783 | if (p != MAP_FAILED) | |
784 | { | |
785 | /* OK, we managed to map the file. Set the buffer up and use a | |
786 | special jump table with simplified underflow functions which | |
787 | never tries to read anything from the file. */ | |
788 | ||
789 | if ( | |
790 | # ifdef _G_LSEEK64 | |
791 | _G_LSEEK64 | |
792 | # else | |
793 | __lseek | |
794 | # endif | |
795 | (fp->_fileno, st.st_size, SEEK_SET) != st.st_size) | |
796 | { | |
797 | (void) __munmap (p, st.st_size); | |
798 | fp->_offset = _IO_pos_BAD; | |
799 | } | |
800 | else | |
801 | { | |
d18ea0c5 | 802 | _IO_setb (fp, p, (char *) p + st.st_size, 0); |
acbee5f6 RM |
803 | |
804 | if (fp->_offset == _IO_pos_BAD) | |
805 | fp->_offset = 0; | |
806 | ||
807 | _IO_setg (fp, p, p + fp->_offset, p + st.st_size); | |
808 | fp->_offset = st.st_size; | |
809 | ||
810 | if (fp->_mode <= 0) | |
811 | _IO_JUMPS ((struct _IO_FILE_plus *)fp) = &_IO_file_jumps_mmap; | |
812 | else | |
813 | _IO_JUMPS ((struct _IO_FILE_plus *)fp) = &_IO_wfile_jumps_mmap; | |
814 | fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap; | |
815 | ||
816 | return; | |
817 | } | |
818 | } | |
819 | } | |
820 | ||
821 | /* We couldn't use mmap, so revert to the vanilla file operations. */ | |
822 | ||
823 | if (fp->_mode <= 0) | |
15a686af | 824 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps; |
acbee5f6 RM |
825 | else |
826 | _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_wfile_jumps; | |
827 | fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; | |
828 | } | |
829 | ||
830 | int | |
831 | _IO_file_underflow_maybe_mmap (_IO_FILE *fp) | |
832 | { | |
833 | /* This is the first read attempt. Choose mmap or vanilla operations | |
834 | and then punt to the chosen underflow routine. */ | |
835 | decide_maybe_mmap (fp); | |
836 | return _IO_UNDERFLOW (fp); | |
837 | } | |
838 | ||
839 | ||
96aa2d94 | 840 | int |
b259e746 | 841 | _IO_new_file_overflow (f, ch) |
40a55d20 UD |
842 | _IO_FILE *f; |
843 | int ch; | |
96aa2d94 RM |
844 | { |
845 | if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ | |
feb3c934 | 846 | { |
c131718c | 847 | f->_flags |= _IO_ERR_SEEN; |
feb3c934 UD |
848 | __set_errno (EBADF); |
849 | return EOF; | |
850 | } | |
96aa2d94 | 851 | /* If currently reading or no buffer allocated. */ |
34c5e4a1 | 852 | if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL) |
96aa2d94 RM |
853 | { |
854 | /* Allocate a buffer if needed. */ | |
34c5e4a1 | 855 | if (f->_IO_write_base == NULL) |
96aa2d94 | 856 | { |
d18ea0c5 | 857 | _IO_doallocbuf (f); |
96aa2d94 RM |
858 | _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); |
859 | } | |
c6645251 UD |
860 | /* Otherwise must be currently reading. |
861 | If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end, | |
862 | logically slide the buffer forwards one block (by setting the | |
863 | read pointers to all point at the beginning of the block). This | |
864 | makes room for subsequent output. | |
865 | Otherwise, set the read pointers to _IO_read_end (leaving that | |
866 | alone, so it can continue to correspond to the external position). */ | |
483b8cc6 UD |
867 | if (__builtin_expect (_IO_in_backup (f), 0)) |
868 | { | |
869 | size_t nbackup = f->_IO_read_end - f->_IO_read_ptr; | |
d18ea0c5 | 870 | _IO_free_backup_area (f); |
483b8cc6 UD |
871 | f->_IO_read_base -= MIN (nbackup, |
872 | f->_IO_read_base - f->_IO_buf_base); | |
873 | f->_IO_read_ptr = f->_IO_read_base; | |
874 | } | |
eb35b097 UD |
875 | |
876 | if (f->_IO_read_ptr == f->_IO_buf_end) | |
877 | f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; | |
878 | f->_IO_write_ptr = f->_IO_read_ptr; | |
879 | f->_IO_write_base = f->_IO_write_ptr; | |
880 | f->_IO_write_end = f->_IO_buf_end; | |
881 | f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; | |
96aa2d94 | 882 | |
96aa2d94 | 883 | f->_flags |= _IO_CURRENTLY_PUTTING; |
076bfcf6 | 884 | if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) |
bfcd44c3 | 885 | f->_IO_write_end = f->_IO_write_ptr; |
96aa2d94 RM |
886 | } |
887 | if (ch == EOF) | |
d18ea0c5 AS |
888 | return _IO_do_write (f, f->_IO_write_base, |
889 | f->_IO_write_ptr - f->_IO_write_base); | |
96aa2d94 | 890 | if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */ |
40a55d20 | 891 | if (_IO_do_flush (f) == EOF) |
96aa2d94 RM |
892 | return EOF; |
893 | *f->_IO_write_ptr++ = ch; | |
894 | if ((f->_flags & _IO_UNBUFFERED) | |
895 | || ((f->_flags & _IO_LINE_BUF) && ch == '\n')) | |
d18ea0c5 AS |
896 | if (_IO_do_write (f, f->_IO_write_base, |
897 | f->_IO_write_ptr - f->_IO_write_base) == EOF) | |
96aa2d94 | 898 | return EOF; |
40a55d20 | 899 | return (unsigned char) ch; |
96aa2d94 | 900 | } |
d18ea0c5 | 901 | libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow) |
96aa2d94 RM |
902 | |
903 | int | |
b259e746 | 904 | _IO_new_file_sync (fp) |
40a55d20 | 905 | _IO_FILE *fp; |
96aa2d94 | 906 | { |
a2bde807 | 907 | _IO_ssize_t delta; |
61eb22d3 UD |
908 | int retval = 0; |
909 | ||
96aa2d94 RM |
910 | /* char* ptr = cur_ptr(); */ |
911 | if (fp->_IO_write_ptr > fp->_IO_write_base) | |
912 | if (_IO_do_flush(fp)) return EOF; | |
23396375 | 913 | delta = fp->_IO_read_ptr - fp->_IO_read_end; |
96aa2d94 RM |
914 | if (delta != 0) |
915 | { | |
916 | #ifdef TODO | |
40a55d20 UD |
917 | if (_IO_in_backup (fp)) |
918 | delta -= eGptr () - Gbase (); | |
96aa2d94 | 919 | #endif |
dfd2257a UD |
920 | _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1); |
921 | if (new_pos != (_IO_off64_t) EOF) | |
96aa2d94 RM |
922 | fp->_IO_read_end = fp->_IO_read_ptr; |
923 | #ifdef ESPIPE | |
924 | else if (errno == ESPIPE) | |
925 | ; /* Ignore error from unseekable devices. */ | |
926 | #endif | |
927 | else | |
61eb22d3 | 928 | retval = EOF; |
96aa2d94 | 929 | } |
61eb22d3 | 930 | if (retval != EOF) |
bd355af0 | 931 | fp->_offset = _IO_pos_BAD; |
96aa2d94 RM |
932 | /* FIXME: Cleanup - can this be shared? */ |
933 | /* setg(base(), ptr, ptr); */ | |
61eb22d3 | 934 | return retval; |
96aa2d94 | 935 | } |
d18ea0c5 | 936 | libc_hidden_ver (_IO_new_file_sync, _IO_file_sync) |
96aa2d94 | 937 | |
acbee5f6 RM |
938 | static int |
939 | _IO_file_sync_mmap (_IO_FILE *fp) | |
940 | { | |
941 | if (fp->_IO_read_ptr != fp->_IO_read_end) | |
942 | { | |
943 | #ifdef TODO | |
944 | if (_IO_in_backup (fp)) | |
945 | delta -= eGptr () - Gbase (); | |
946 | #endif | |
947 | if ( | |
948 | # ifdef _G_LSEEK64 | |
949 | _G_LSEEK64 | |
950 | # else | |
951 | __lseek | |
952 | # endif | |
953 | (fp->_fileno, fp->_IO_read_ptr - fp->_IO_buf_base, SEEK_SET) | |
954 | != fp->_IO_read_ptr - fp->_IO_buf_base) | |
955 | { | |
956 | fp->_flags |= _IO_ERR_SEEN; | |
957 | return EOF; | |
958 | } | |
959 | } | |
960 | fp->_offset = fp->_IO_read_ptr - fp->_IO_buf_base; | |
961 | fp->_IO_read_end = fp->_IO_read_ptr = fp->_IO_read_base; | |
962 | return 0; | |
963 | } | |
964 | ||
965 | ||
d64b6ad0 | 966 | _IO_off64_t |
b259e746 | 967 | _IO_new_file_seekoff (fp, offset, dir, mode) |
40a55d20 | 968 | _IO_FILE *fp; |
dfd2257a | 969 | _IO_off64_t offset; |
40a55d20 UD |
970 | int dir; |
971 | int mode; | |
96aa2d94 | 972 | { |
d64b6ad0 | 973 | _IO_off64_t result; |
dfd2257a | 974 | _IO_off64_t delta, new_offset; |
96aa2d94 | 975 | long count; |
feb3c934 UD |
976 | /* POSIX.1 8.2.3.7 says that after a call the fflush() the file |
977 | offset of the underlying file must be exact. */ | |
978 | int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end | |
979 | && fp->_IO_write_base == fp->_IO_write_ptr); | |
96aa2d94 RM |
980 | |
981 | if (mode == 0) | |
982 | dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ | |
983 | ||
984 | /* Flush unwritten characters. | |
985 | (This may do an unneeded write if we seek within the buffer. | |
986 | But to be able to switch to reading, we would need to set | |
987 | egptr to ptr. That can't be done in the current design, | |
988 | which assumes file_ptr() is eGptr. Anyway, since we probably | |
989 | end up flushing when we close(), it doesn't make much difference.) | |
990 | FIXME: simulate mem-papped files. */ | |
991 | ||
40a55d20 | 992 | if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp)) |
d18ea0c5 | 993 | if (_IO_switch_to_get_mode (fp)) |
40a55d20 | 994 | return EOF; |
96aa2d94 RM |
995 | |
996 | if (fp->_IO_buf_base == NULL) | |
997 | { | |
00bc5db0 UD |
998 | /* It could be that we already have a pushback buffer. */ |
999 | if (fp->_IO_read_base != NULL) | |
1000 | { | |
1001 | free (fp->_IO_read_base); | |
1002 | fp->_flags &= ~_IO_IN_BACKUP; | |
1003 | } | |
d18ea0c5 | 1004 | _IO_doallocbuf (fp); |
40a55d20 UD |
1005 | _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); |
1006 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); | |
96aa2d94 RM |
1007 | } |
1008 | ||
1009 | switch (dir) | |
1010 | { | |
1011 | case _IO_seek_cur: | |
1012 | /* Adjust for read-ahead (bytes is buffer). */ | |
1013 | offset -= fp->_IO_read_end - fp->_IO_read_ptr; | |
bd355af0 | 1014 | if (fp->_offset == _IO_pos_BAD) |
b722481a EB |
1015 | { |
1016 | if (mode != 0) | |
1017 | goto dumb; | |
1018 | else | |
1019 | { | |
1020 | result = _IO_SYSSEEK (fp, 0, dir); | |
1021 | if (result == EOF) | |
1022 | return result; | |
1023 | ||
1024 | fp->_offset = result; | |
1025 | } | |
1026 | } | |
96aa2d94 | 1027 | /* Make offset absolute, assuming current pointer is file_ptr(). */ |
d64b6ad0 | 1028 | offset += fp->_offset; |
405550bf UD |
1029 | if (offset < 0) |
1030 | { | |
1031 | __set_errno (EINVAL); | |
1032 | return EOF; | |
1033 | } | |
96aa2d94 RM |
1034 | |
1035 | dir = _IO_seek_set; | |
1036 | break; | |
1037 | case _IO_seek_set: | |
1038 | break; | |
1039 | case _IO_seek_end: | |
1040 | { | |
dfd2257a | 1041 | struct _G_stat64 st; |
40a55d20 | 1042 | if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)) |
96aa2d94 RM |
1043 | { |
1044 | offset += st.st_size; | |
1045 | dir = _IO_seek_set; | |
1046 | } | |
1047 | else | |
1048 | goto dumb; | |
1049 | } | |
1050 | } | |
1051 | /* At this point, dir==_IO_seek_set. */ | |
1052 | ||
00bc5db0 UD |
1053 | /* If we are only interested in the current position we've found it now. */ |
1054 | if (mode == 0) | |
1055 | return offset; | |
1056 | ||
96aa2d94 | 1057 | /* If destination is within current buffer, optimize: */ |
bd355af0 | 1058 | if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL |
96aa2d94 RM |
1059 | && !_IO_in_backup (fp)) |
1060 | { | |
c03c66dd UD |
1061 | _IO_off64_t start_offset = (fp->_offset |
1062 | - (fp->_IO_read_end - fp->_IO_buf_base)); | |
1063 | if (offset >= start_offset && offset < fp->_offset) | |
96aa2d94 | 1064 | { |
c03c66dd UD |
1065 | _IO_setg (fp, fp->_IO_buf_base, |
1066 | fp->_IO_buf_base + (offset - start_offset), | |
1067 | fp->_IO_read_end); | |
1068 | _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); | |
1069 | ||
00bc5db0 | 1070 | _IO_mask_flags (fp, 0, _IO_EOF_SEEN); |
4a582094 | 1071 | goto resync; |
96aa2d94 | 1072 | } |
96aa2d94 RM |
1073 | } |
1074 | ||
96aa2d94 RM |
1075 | if (fp->_flags & _IO_NO_READS) |
1076 | goto dumb; | |
1077 | ||
1078 | /* Try to seek to a block boundary, to improve kernel page management. */ | |
1079 | new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1); | |
1080 | delta = offset - new_offset; | |
1081 | if (delta > fp->_IO_buf_end - fp->_IO_buf_base) | |
1082 | { | |
1083 | new_offset = offset; | |
1084 | delta = 0; | |
1085 | } | |
1086 | result = _IO_SYSSEEK (fp, new_offset, 0); | |
1087 | if (result < 0) | |
1088 | return EOF; | |
1089 | if (delta == 0) | |
1090 | count = 0; | |
1091 | else | |
1092 | { | |
1093 | count = _IO_SYSREAD (fp, fp->_IO_buf_base, | |
feb3c934 UD |
1094 | (must_be_exact |
1095 | ? delta : fp->_IO_buf_end - fp->_IO_buf_base)); | |
96aa2d94 RM |
1096 | if (count < delta) |
1097 | { | |
1098 | /* We weren't allowed to read, but try to seek the remainder. */ | |
1099 | offset = count == EOF ? delta : delta-count; | |
1100 | dir = _IO_seek_cur; | |
1101 | goto dumb; | |
1102 | } | |
1103 | } | |
40a55d20 UD |
1104 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta, |
1105 | fp->_IO_buf_base + count); | |
1106 | _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); | |
bd355af0 | 1107 | fp->_offset = result + count; |
40a55d20 | 1108 | _IO_mask_flags (fp, 0, _IO_EOF_SEEN); |
96aa2d94 RM |
1109 | return offset; |
1110 | dumb: | |
1111 | ||
d18ea0c5 | 1112 | _IO_unsave_markers (fp); |
96aa2d94 RM |
1113 | result = _IO_SYSSEEK (fp, offset, dir); |
1114 | if (result != EOF) | |
d762684b UD |
1115 | { |
1116 | _IO_mask_flags (fp, 0, _IO_EOF_SEEN); | |
1117 | fp->_offset = result; | |
1118 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); | |
1119 | _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); | |
1120 | } | |
96aa2d94 | 1121 | return result; |
4a582094 UD |
1122 | |
1123 | resync: | |
1124 | /* We need to do it since it is possible that the file offset in | |
1125 | the kernel may be changed behind our back. It may happen when | |
1126 | we fopen a file and then do a fork. One process may access the | |
ded5b9b7 | 1127 | file and the kernel file offset will be changed. */ |
4a582094 UD |
1128 | if (fp->_offset >= 0) |
1129 | _IO_SYSSEEK (fp, fp->_offset, 0); | |
1130 | ||
1131 | return offset; | |
96aa2d94 | 1132 | } |
d18ea0c5 | 1133 | libc_hidden_ver (_IO_new_file_seekoff, _IO_file_seekoff) |
96aa2d94 | 1134 | |
284749da UD |
1135 | _IO_off64_t |
1136 | _IO_file_seekoff_mmap (fp, offset, dir, mode) | |
1137 | _IO_FILE *fp; | |
1138 | _IO_off64_t offset; | |
1139 | int dir; | |
1140 | int mode; | |
1141 | { | |
1142 | _IO_off64_t result; | |
1143 | ||
7e93f915 RM |
1144 | /* If we are only interested in the current position, calculate it and |
1145 | return right now. This calculation does the right thing when we are | |
1146 | using a pushback buffer, but in the usual case has the same value as | |
1147 | (fp->_IO_read_ptr - fp->_IO_buf_base). */ | |
284749da | 1148 | if (mode == 0) |
78ce5a3b | 1149 | return fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr); |
284749da UD |
1150 | |
1151 | switch (dir) | |
1152 | { | |
1153 | case _IO_seek_cur: | |
1154 | /* Adjust for read-ahead (bytes is buffer). */ | |
1155 | offset += fp->_IO_read_ptr - fp->_IO_read_base; | |
1156 | break; | |
1157 | case _IO_seek_set: | |
1158 | break; | |
1159 | case _IO_seek_end: | |
903b3396 | 1160 | offset += fp->_IO_buf_end - fp->_IO_buf_base; |
284749da UD |
1161 | break; |
1162 | } | |
1163 | /* At this point, dir==_IO_seek_set. */ | |
1164 | ||
1165 | if (offset < 0) | |
66bff409 UD |
1166 | { |
1167 | /* No negative offsets are valid. */ | |
1168 | __set_errno (EINVAL); | |
1169 | return EOF; | |
1170 | } | |
284749da | 1171 | |
284749da UD |
1172 | result = _IO_SYSSEEK (fp, offset, 0); |
1173 | if (result < 0) | |
1174 | return EOF; | |
1175 | ||
fc77d66a RM |
1176 | if (offset > fp->_IO_buf_end - fp->_IO_buf_base) |
1177 | /* One can fseek arbitrarily past the end of the file | |
1178 | and it is meaningless until one attempts to read. | |
1179 | Leave the buffer pointers in EOF state until underflow. */ | |
1180 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_end, fp->_IO_buf_end); | |
1181 | else | |
1182 | /* Adjust the read pointers to match the file position, | |
1183 | but so the next read attempt will call underflow. */ | |
1184 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset, | |
1185 | fp->_IO_buf_base + offset); | |
1186 | ||
66bff409 | 1187 | fp->_offset = result; |
284749da UD |
1188 | |
1189 | _IO_mask_flags (fp, 0, _IO_EOF_SEEN); | |
1190 | ||
1191 | return offset; | |
1192 | } | |
1193 | ||
f5bf21a7 UD |
1194 | static _IO_off64_t |
1195 | _IO_file_seekoff_maybe_mmap (_IO_FILE *fp, _IO_off64_t offset, int dir, | |
1196 | int mode) | |
acbee5f6 RM |
1197 | { |
1198 | /* We only get here when we haven't tried to read anything yet. | |
1199 | So there is nothing more useful for us to do here than just | |
1200 | the underlying lseek call. */ | |
1201 | ||
1202 | _IO_off64_t result = _IO_SYSSEEK (fp, offset, dir); | |
1203 | if (result < 0) | |
1204 | return EOF; | |
1205 | ||
1206 | fp->_offset = result; | |
1207 | return result; | |
1208 | } | |
1209 | ||
96aa2d94 | 1210 | _IO_ssize_t |
40a55d20 UD |
1211 | _IO_file_read (fp, buf, size) |
1212 | _IO_FILE *fp; | |
1213 | void *buf; | |
1214 | _IO_ssize_t size; | |
96aa2d94 | 1215 | { |
e3c54d80 | 1216 | return (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0) |
ee8449f7 UD |
1217 | ? read_not_cancel (fp->_fileno, buf, size) |
1218 | : read (fp->_fileno, buf, size)); | |
96aa2d94 | 1219 | } |
d18ea0c5 | 1220 | libc_hidden_def (_IO_file_read) |
96aa2d94 | 1221 | |
d64b6ad0 | 1222 | _IO_off64_t |
40a55d20 UD |
1223 | _IO_file_seek (fp, offset, dir) |
1224 | _IO_FILE *fp; | |
dfd2257a | 1225 | _IO_off64_t offset; |
40a55d20 | 1226 | int dir; |
96aa2d94 | 1227 | { |
dfd2257a UD |
1228 | #ifdef _G_LSEEK64 |
1229 | return _G_LSEEK64 (fp->_fileno, offset, dir); | |
1230 | #else | |
61eb22d3 | 1231 | return lseek (fp->_fileno, offset, dir); |
dfd2257a | 1232 | #endif |
96aa2d94 | 1233 | } |
d18ea0c5 | 1234 | libc_hidden_def (_IO_file_seek) |
96aa2d94 RM |
1235 | |
1236 | int | |
40a55d20 UD |
1237 | _IO_file_stat (fp, st) |
1238 | _IO_FILE *fp; | |
1239 | void *st; | |
96aa2d94 | 1240 | { |
279eb600 | 1241 | #ifdef _G_FSTAT64 |
dfd2257a UD |
1242 | return _G_FSTAT64 (fp->_fileno, (struct _G_stat64 *) st); |
1243 | #else | |
319d719d | 1244 | return fstat (fp->_fileno, (struct stat *) st); |
dfd2257a | 1245 | #endif |
96aa2d94 | 1246 | } |
d18ea0c5 | 1247 | libc_hidden_def (_IO_file_stat) |
96aa2d94 | 1248 | |
0469311e UD |
1249 | int |
1250 | _IO_file_close_mmap (fp) | |
1251 | _IO_FILE *fp; | |
1252 | { | |
acbee5f6 RM |
1253 | /* In addition to closing the file descriptor we have to unmap the file. */ |
1254 | (void) __munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base); | |
0469311e | 1255 | fp->_IO_buf_base = fp->_IO_buf_end = NULL; |
73299943 UD |
1256 | /* Cancelling close should be avoided if possible since it leaves an |
1257 | unrecoverable state behind. */ | |
1258 | return close_not_cancel (fp->_fileno); | |
0469311e UD |
1259 | } |
1260 | ||
96aa2d94 | 1261 | int |
40a55d20 UD |
1262 | _IO_file_close (fp) |
1263 | _IO_FILE *fp; | |
96aa2d94 | 1264 | { |
73299943 UD |
1265 | /* Cancelling close should be avoided if possible since it leaves an |
1266 | unrecoverable state behind. */ | |
1267 | return close_not_cancel (fp->_fileno); | |
96aa2d94 | 1268 | } |
d18ea0c5 | 1269 | libc_hidden_def (_IO_file_close) |
96aa2d94 RM |
1270 | |
1271 | _IO_ssize_t | |
b259e746 | 1272 | _IO_new_file_write (f, data, n) |
40a55d20 UD |
1273 | _IO_FILE *f; |
1274 | const void *data; | |
1275 | _IO_ssize_t n; | |
96aa2d94 RM |
1276 | { |
1277 | _IO_ssize_t to_do = n; | |
1278 | while (to_do > 0) | |
1279 | { | |
e3c54d80 UD |
1280 | _IO_ssize_t count = (__builtin_expect (f->_flags2 |
1281 | & _IO_FLAGS2_NOTCANCEL, 0) | |
ee8449f7 UD |
1282 | ? write_not_cancel (f->_fileno, data, to_do) |
1283 | : write (f->_fileno, data, to_do)); | |
d64b6ad0 | 1284 | if (count < 0) |
96aa2d94 | 1285 | { |
39e16978 UD |
1286 | f->_flags |= _IO_ERR_SEEN; |
1287 | break; | |
b722481a | 1288 | } |
96aa2d94 | 1289 | to_do -= count; |
40a55d20 | 1290 | data = (void *) ((char *) data + count); |
96aa2d94 RM |
1291 | } |
1292 | n -= to_do; | |
bd355af0 UD |
1293 | if (f->_offset >= 0) |
1294 | f->_offset += n; | |
96aa2d94 RM |
1295 | return n; |
1296 | } | |
1297 | ||
1298 | _IO_size_t | |
b259e746 | 1299 | _IO_new_file_xsputn (f, data, n) |
40a55d20 UD |
1300 | _IO_FILE *f; |
1301 | const void *data; | |
1302 | _IO_size_t n; | |
96aa2d94 | 1303 | { |
d64b6ad0 | 1304 | register const char *s = (const char *) data; |
96aa2d94 RM |
1305 | _IO_size_t to_do = n; |
1306 | int must_flush = 0; | |
cae6ebb2 | 1307 | _IO_size_t count = 0; |
96aa2d94 RM |
1308 | |
1309 | if (n <= 0) | |
1310 | return 0; | |
1311 | /* This is an optimized implementation. | |
1312 | If the amount to be written straddles a block boundary | |
1313 | (or the filebuf is unbuffered), use sys_write directly. */ | |
1314 | ||
1315 | /* First figure out how much space is available in the buffer. */ | |
96aa2d94 RM |
1316 | if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) |
1317 | { | |
1318 | count = f->_IO_buf_end - f->_IO_write_ptr; | |
1319 | if (count >= n) | |
40a55d20 UD |
1320 | { |
1321 | register const char *p; | |
96aa2d94 RM |
1322 | for (p = s + n; p > s; ) |
1323 | { | |
40a55d20 UD |
1324 | if (*--p == '\n') |
1325 | { | |
1326 | count = p - s + 1; | |
1327 | must_flush = 1; | |
1328 | break; | |
1329 | } | |
96aa2d94 RM |
1330 | } |
1331 | } | |
1332 | } | |
cae6ebb2 UD |
1333 | else if (f->_IO_write_end > f->_IO_write_ptr) |
1334 | count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */ | |
1335 | ||
96aa2d94 RM |
1336 | /* Then fill the buffer. */ |
1337 | if (count > 0) | |
1338 | { | |
1339 | if (count > to_do) | |
1340 | count = to_do; | |
86187531 | 1341 | #ifdef _LIBC |
20fde227 | 1342 | f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count); |
86187531 | 1343 | #else |
20fde227 DM |
1344 | memcpy (f->_IO_write_ptr, s, count); |
1345 | f->_IO_write_ptr += count; | |
86187531 | 1346 | #endif |
20fde227 | 1347 | s += count; |
96aa2d94 RM |
1348 | to_do -= count; |
1349 | } | |
1350 | if (to_do + must_flush > 0) | |
40a55d20 | 1351 | { |
0720f75c | 1352 | _IO_size_t block_size, do_write; |
96aa2d94 | 1353 | /* Next flush the (full) buffer. */ |
5c8d1fc0 | 1354 | if (_IO_OVERFLOW (f, EOF) == EOF) |
34c5e4a1 UD |
1355 | /* If nothing else has to be written we must not signal the |
1356 | caller that everything has been written. */ | |
1357 | return to_do == 0 ? EOF : n - to_do; | |
96aa2d94 RM |
1358 | |
1359 | /* Try to maintain alignment: write a whole number of blocks. | |
1360 | dont_write is what gets left over. */ | |
1361 | block_size = f->_IO_buf_end - f->_IO_buf_base; | |
0720f75c UD |
1362 | do_write = to_do - (block_size >= 128 ? to_do % block_size : 0); |
1363 | ||
1364 | if (do_write) | |
b722481a | 1365 | { |
0720f75c UD |
1366 | count = new_do_write (f, s, do_write); |
1367 | to_do -= count; | |
1368 | if (count < do_write) | |
1369 | return n - to_do; | |
b722481a | 1370 | } |
23396375 | 1371 | |
96aa2d94 RM |
1372 | /* Now write out the remainder. Normally, this will fit in the |
1373 | buffer, but it's somewhat messier for line-buffered files, | |
1374 | so we let _IO_default_xsputn handle the general case. */ | |
0720f75c | 1375 | if (to_do) |
d18ea0c5 | 1376 | to_do -= _IO_default_xsputn (f, s+do_write, to_do); |
96aa2d94 RM |
1377 | } |
1378 | return n - to_do; | |
1379 | } | |
d18ea0c5 | 1380 | libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn) |
96aa2d94 | 1381 | |
96aa2d94 | 1382 | _IO_size_t |
40a55d20 UD |
1383 | _IO_file_xsgetn (fp, data, n) |
1384 | _IO_FILE *fp; | |
1385 | void *data; | |
1386 | _IO_size_t n; | |
96aa2d94 | 1387 | { |
4bca4c17 UD |
1388 | register _IO_size_t want, have; |
1389 | register _IO_ssize_t count; | |
96aa2d94 | 1390 | register char *s = data; |
8fe0fd03 UD |
1391 | |
1392 | want = n; | |
1393 | ||
310f9518 UD |
1394 | if (fp->_IO_buf_base == NULL) |
1395 | { | |
1396 | /* Maybe we already have a push back pointer. */ | |
1397 | if (fp->_IO_save_base != NULL) | |
1398 | { | |
1399 | free (fp->_IO_save_base); | |
1400 | fp->_flags &= ~_IO_IN_BACKUP; | |
1401 | } | |
d18ea0c5 | 1402 | _IO_doallocbuf (fp); |
310f9518 UD |
1403 | } |
1404 | ||
8fe0fd03 | 1405 | while (want > 0) |
96aa2d94 | 1406 | { |
8fe0fd03 UD |
1407 | have = fp->_IO_read_end - fp->_IO_read_ptr; |
1408 | if (want <= have) | |
96aa2d94 | 1409 | { |
8fe0fd03 UD |
1410 | memcpy (s, fp->_IO_read_ptr, want); |
1411 | fp->_IO_read_ptr += want; | |
1412 | want = 0; | |
1413 | } | |
1414 | else | |
1415 | { | |
1416 | if (have > 0) | |
96aa2d94 | 1417 | { |
279eb600 UD |
1418 | #ifdef _LIBC |
1419 | s = __mempcpy (s, fp->_IO_read_ptr, have); | |
1420 | #else | |
8fe0fd03 | 1421 | memcpy (s, fp->_IO_read_ptr, have); |
8fe0fd03 | 1422 | s += have; |
279eb600 UD |
1423 | #endif |
1424 | want -= have; | |
8fe0fd03 | 1425 | fp->_IO_read_ptr += have; |
96aa2d94 | 1426 | } |
8fe0fd03 UD |
1427 | |
1428 | /* Check for backup and repeat */ | |
1429 | if (_IO_in_backup (fp)) | |
96aa2d94 | 1430 | { |
8fe0fd03 UD |
1431 | _IO_switch_to_main_get_area (fp); |
1432 | continue; | |
1433 | } | |
1434 | ||
1435 | /* If we now want less than a buffer, underflow and repeat | |
1436 | the copy. Otherwise, _IO_SYSREAD directly to | |
1437 | the user buffer. */ | |
6dd67bd5 UD |
1438 | if (fp->_IO_buf_base |
1439 | && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base)) | |
8fe0fd03 UD |
1440 | { |
1441 | if (__underflow (fp) == EOF) | |
1442 | break; | |
1443 | ||
1444 | continue; | |
1445 | } | |
1446 | ||
4bca4c17 UD |
1447 | /* These must be set before the sysread as we might longjmp out |
1448 | waiting for input. */ | |
1449 | _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); | |
1450 | _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); | |
1451 | ||
279eb600 UD |
1452 | /* Try to maintain alignment: read a whole number of blocks. */ |
1453 | count = want; | |
1454 | if (fp->_IO_buf_base) | |
1455 | { | |
1456 | _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base; | |
1457 | if (block_size >= 128) | |
1458 | count -= want % block_size; | |
1459 | } | |
1460 | ||
1461 | count = _IO_SYSREAD (fp, s, count); | |
96aa2d94 | 1462 | if (count <= 0) |
8fe0fd03 UD |
1463 | { |
1464 | if (count == 0) | |
1465 | fp->_flags |= _IO_EOF_SEEN; | |
1466 | else | |
1467 | fp->_flags |= _IO_ERR_SEEN; | |
1468 | ||
1469 | break; | |
1470 | } | |
23396375 | 1471 | |
96aa2d94 | 1472 | s += count; |
8fe0fd03 | 1473 | want -= count; |
4bca4c17 UD |
1474 | if (fp->_offset != _IO_pos_BAD) |
1475 | _IO_pos_adjust (fp->_offset, count); | |
96aa2d94 | 1476 | } |
96aa2d94 | 1477 | } |
8fe0fd03 UD |
1478 | |
1479 | return n - want; | |
96aa2d94 | 1480 | } |
d18ea0c5 | 1481 | libc_hidden_def (_IO_file_xsgetn) |
96aa2d94 | 1482 | |
0fca3153 | 1483 | static _IO_size_t _IO_file_xsgetn_mmap (_IO_FILE *, void *, _IO_size_t); |
284749da UD |
1484 | static _IO_size_t |
1485 | _IO_file_xsgetn_mmap (fp, data, n) | |
1486 | _IO_FILE *fp; | |
1487 | void *data; | |
1488 | _IO_size_t n; | |
1489 | { | |
1490 | register _IO_size_t have; | |
1491 | char *read_ptr = fp->_IO_read_ptr; | |
b39d5719 | 1492 | register char *s = (char *) data; |
284749da UD |
1493 | |
1494 | have = fp->_IO_read_end - fp->_IO_read_ptr; | |
1495 | ||
1496 | if (have < n) | |
1497 | { | |
b39d5719 UD |
1498 | if (__builtin_expect (_IO_in_backup (fp), 0)) |
1499 | { | |
1500 | #ifdef _LIBC | |
1501 | s = __mempcpy (s, read_ptr, have); | |
1502 | #else | |
1503 | memcpy (s, read_ptr, have); | |
1504 | s += have; | |
1505 | #endif | |
1506 | n -= have; | |
1507 | _IO_switch_to_main_get_area (fp); | |
1508 | read_ptr = fp->_IO_read_ptr; | |
1509 | have = fp->_IO_read_end - fp->_IO_read_ptr; | |
1510 | } | |
1511 | ||
1512 | if (have < n) | |
1513 | { | |
acbee5f6 RM |
1514 | /* Check that we are mapping all of the file, in case it grew. */ |
1515 | if (__builtin_expect (mmap_remap_check (fp), 0)) | |
1516 | /* We punted mmap, so complete with the vanilla code. */ | |
1517 | return s - (char *) data + _IO_XSGETN (fp, data, n); | |
1518 | ||
1519 | read_ptr = fp->_IO_read_ptr; | |
1520 | have = fp->_IO_read_end - read_ptr; | |
b39d5719 | 1521 | } |
284749da UD |
1522 | } |
1523 | ||
c4292489 UD |
1524 | if (have < n) |
1525 | fp->_flags |= _IO_EOF_SEEN; | |
1526 | ||
1527 | if (have != 0) | |
284749da UD |
1528 | { |
1529 | have = MIN (have, n); | |
b39d5719 UD |
1530 | #ifdef _LIBC |
1531 | s = __mempcpy (s, read_ptr, have); | |
1532 | #else | |
1533 | memcpy (s, read_ptr, have); | |
1534 | s += have; | |
1535 | #endif | |
284749da UD |
1536 | fp->_IO_read_ptr = read_ptr + have; |
1537 | } | |
1538 | ||
b39d5719 | 1539 | return s - (char *) data; |
284749da UD |
1540 | } |
1541 | ||
0fca3153 | 1542 | static _IO_size_t _IO_file_xsgetn_maybe_mmap (_IO_FILE *, void *, _IO_size_t); |
acbee5f6 RM |
1543 | static _IO_size_t |
1544 | _IO_file_xsgetn_maybe_mmap (fp, data, n) | |
1545 | _IO_FILE *fp; | |
1546 | void *data; | |
1547 | _IO_size_t n; | |
1548 | { | |
1549 | /* We only get here if this is the first attempt to read something. | |
1550 | Decide which operations to use and then punt to the chosen one. */ | |
1551 | ||
1552 | decide_maybe_mmap (fp); | |
1553 | return _IO_XSGETN (fp, data, n); | |
1554 | } | |
1555 | ||
94b68ee9 RM |
1556 | #ifdef _LIBC |
1557 | versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1); | |
1558 | versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1); | |
1559 | versioned_symbol (libc, _IO_new_file_close_it, _IO_file_close_it, GLIBC_2_1); | |
1560 | versioned_symbol (libc, _IO_new_file_finish, _IO_file_finish, GLIBC_2_1); | |
1561 | versioned_symbol (libc, _IO_new_file_fopen, _IO_file_fopen, GLIBC_2_1); | |
1562 | versioned_symbol (libc, _IO_new_file_init, _IO_file_init, GLIBC_2_1); | |
1563 | versioned_symbol (libc, _IO_new_file_setbuf, _IO_file_setbuf, GLIBC_2_1); | |
1564 | versioned_symbol (libc, _IO_new_file_sync, _IO_file_sync, GLIBC_2_1); | |
1565 | versioned_symbol (libc, _IO_new_file_overflow, _IO_file_overflow, GLIBC_2_1); | |
1566 | versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1); | |
1567 | versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1); | |
1568 | versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1); | |
1569 | versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1); | |
1570 | #endif | |
1571 | ||
b2637a22 | 1572 | const struct _IO_jump_t _IO_file_jumps = |
40a55d20 | 1573 | { |
96aa2d94 | 1574 | JUMP_INIT_DUMMY, |
d18ea0c5 AS |
1575 | JUMP_INIT(finish, _IO_file_finish), |
1576 | JUMP_INIT(overflow, _IO_file_overflow), | |
1577 | JUMP_INIT(underflow, _IO_file_underflow), | |
1578 | JUMP_INIT(uflow, _IO_default_uflow), | |
1579 | JUMP_INIT(pbackfail, _IO_default_pbackfail), | |
1580 | JUMP_INIT(xsputn, _IO_file_xsputn), | |
1581 | JUMP_INIT(xsgetn, _IO_file_xsgetn), | |
b259e746 | 1582 | JUMP_INIT(seekoff, _IO_new_file_seekoff), |
96aa2d94 | 1583 | JUMP_INIT(seekpos, _IO_default_seekpos), |
b259e746 UD |
1584 | JUMP_INIT(setbuf, _IO_new_file_setbuf), |
1585 | JUMP_INIT(sync, _IO_new_file_sync), | |
d18ea0c5 AS |
1586 | JUMP_INIT(doallocate, _IO_file_doallocate), |
1587 | JUMP_INIT(read, _IO_file_read), | |
b259e746 | 1588 | JUMP_INIT(write, _IO_new_file_write), |
d18ea0c5 AS |
1589 | JUMP_INIT(seek, _IO_file_seek), |
1590 | JUMP_INIT(close, _IO_file_close), | |
1591 | JUMP_INIT(stat, _IO_file_stat), | |
dfd2257a | 1592 | JUMP_INIT(showmanyc, _IO_default_showmanyc), |
0469311e UD |
1593 | JUMP_INIT(imbue, _IO_default_imbue) |
1594 | }; | |
15a686af | 1595 | libc_hidden_data_def (_IO_file_jumps) |
0469311e | 1596 | |
b2637a22 | 1597 | const struct _IO_jump_t _IO_file_jumps_mmap = |
0469311e UD |
1598 | { |
1599 | JUMP_INIT_DUMMY, | |
d18ea0c5 AS |
1600 | JUMP_INIT(finish, _IO_file_finish), |
1601 | JUMP_INIT(overflow, _IO_file_overflow), | |
0469311e | 1602 | JUMP_INIT(underflow, _IO_file_underflow_mmap), |
d18ea0c5 AS |
1603 | JUMP_INIT(uflow, _IO_default_uflow), |
1604 | JUMP_INIT(pbackfail, _IO_default_pbackfail), | |
0469311e | 1605 | JUMP_INIT(xsputn, _IO_new_file_xsputn), |
284749da UD |
1606 | JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap), |
1607 | JUMP_INIT(seekoff, _IO_file_seekoff_mmap), | |
0469311e | 1608 | JUMP_INIT(seekpos, _IO_default_seekpos), |
bff334e0 | 1609 | JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap), |
acbee5f6 | 1610 | JUMP_INIT(sync, _IO_file_sync_mmap), |
d18ea0c5 AS |
1611 | JUMP_INIT(doallocate, _IO_file_doallocate), |
1612 | JUMP_INIT(read, _IO_file_read), | |
0469311e | 1613 | JUMP_INIT(write, _IO_new_file_write), |
d18ea0c5 | 1614 | JUMP_INIT(seek, _IO_file_seek), |
0469311e | 1615 | JUMP_INIT(close, _IO_file_close_mmap), |
d18ea0c5 | 1616 | JUMP_INIT(stat, _IO_file_stat), |
0469311e | 1617 | JUMP_INIT(showmanyc, _IO_default_showmanyc), |
acbee5f6 RM |
1618 | JUMP_INIT(imbue, _IO_default_imbue) |
1619 | }; | |
1620 | ||
b2637a22 | 1621 | const struct _IO_jump_t _IO_file_jumps_maybe_mmap = |
acbee5f6 RM |
1622 | { |
1623 | JUMP_INIT_DUMMY, | |
d18ea0c5 AS |
1624 | JUMP_INIT(finish, _IO_file_finish), |
1625 | JUMP_INIT(overflow, _IO_file_overflow), | |
acbee5f6 | 1626 | JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap), |
d18ea0c5 AS |
1627 | JUMP_INIT(uflow, _IO_default_uflow), |
1628 | JUMP_INIT(pbackfail, _IO_default_pbackfail), | |
acbee5f6 RM |
1629 | JUMP_INIT(xsputn, _IO_new_file_xsputn), |
1630 | JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap), | |
1631 | JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap), | |
1632 | JUMP_INIT(seekpos, _IO_default_seekpos), | |
1633 | JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap), | |
1634 | JUMP_INIT(sync, _IO_new_file_sync), | |
d18ea0c5 AS |
1635 | JUMP_INIT(doallocate, _IO_file_doallocate), |
1636 | JUMP_INIT(read, _IO_file_read), | |
acbee5f6 | 1637 | JUMP_INIT(write, _IO_new_file_write), |
d18ea0c5 | 1638 | JUMP_INIT(seek, _IO_file_seek), |
acbee5f6 | 1639 | JUMP_INIT(close, _IO_file_close), |
d18ea0c5 | 1640 | JUMP_INIT(stat, _IO_file_stat), |
acbee5f6 | 1641 | JUMP_INIT(showmanyc, _IO_default_showmanyc), |
dfd2257a | 1642 | JUMP_INIT(imbue, _IO_default_imbue) |
96aa2d94 | 1643 | }; |