vfs: check userland buffers before reading them.
[haiku.git] / src / system / libroot / posix / glibc / libio / wfileops.c
blob382220c6f30dc8871404f99ef002176e25dfc321
1 /* Copyright (C) 1993,95,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Written by Ulrich Drepper <drepper@cygnus.com>.
4 Based on the single byte version by Per Bothner <bothner@cygnus.com>.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 As a special exception, if you link the code in this file with
22 files compiled with a GNU compiler to produce an executable,
23 that does not cause the resulting executable to be covered by
24 the GNU Lesser General Public License. This exception does not
25 however invalidate any other reasons why the executable file
26 might be covered by the GNU Lesser General Public License.
27 This exception applies to code released by its copyright holders
28 in files containing the exception. */
30 #include <assert.h>
31 #include <libioP.h>
32 #include <wchar.h>
33 #include <gconv.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
39 #ifndef _LIBC
40 # define _IO_new_do_write _IO_do_write
41 # define _IO_new_file_attach _IO_file_attach
42 # define _IO_new_file_close_it _IO_file_close_it
43 # define _IO_new_file_finish _IO_file_finish
44 # define _IO_new_file_fopen _IO_file_fopen
45 # define _IO_new_file_init _IO_file_init
46 # define _IO_new_file_setbuf _IO_file_setbuf
47 # define _IO_new_file_sync _IO_file_sync
48 # define _IO_new_file_overflow _IO_file_overflow
49 # define _IO_new_file_seekoff _IO_file_seekoff
50 # define _IO_new_file_underflow _IO_file_underflow
51 # define _IO_new_file_write _IO_file_write
52 # define _IO_new_file_xsputn _IO_file_xsputn
53 #endif
56 /* Convert TO_DO wide character from DATA to FP.
57 Then mark FP as having empty buffers. */
58 int
59 _IO_wdo_write (fp, data, to_do)
60 _IO_FILE *fp;
61 const wchar_t *data;
62 _IO_size_t to_do;
64 struct _IO_codecvt *cc = fp->_codecvt;
66 if (to_do > 0)
68 if (fp->_IO_write_end == fp->_IO_write_ptr
69 && fp->_IO_write_end != fp->_IO_write_base)
71 if (_IO_new_do_write (fp, fp->_IO_write_base,
72 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
73 return EOF;
78 enum __codecvt_result result;
79 const wchar_t *new_data;
81 /* Now convert from the internal format into the external buffer. */
82 result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
83 data, data + to_do, &new_data,
84 fp->_IO_write_ptr,
85 fp->_IO_buf_end,
86 &fp->_IO_write_ptr);
88 /* Write out what we produced so far. */
89 if (_IO_new_do_write (fp, fp->_IO_write_base,
90 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
91 /* Something went wrong. */
92 return WEOF;
94 to_do -= new_data - data;
96 /* Next see whether we had problems during the conversion. If yes,
97 we cannot go on. */
98 if (result != __codecvt_ok
99 && (result != __codecvt_partial || new_data - data == 0))
100 break;
102 data = new_data;
104 while (to_do > 0);
107 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
108 fp->_wide_data->_IO_buf_base);
109 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
110 = fp->_wide_data->_IO_buf_base;
111 fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
112 ? fp->_wide_data->_IO_buf_base
113 : fp->_wide_data->_IO_buf_end);
115 return to_do == 0 ? 0 : WEOF;
117 INTDEF(_IO_wdo_write)
120 wint_t
121 _IO_wfile_underflow (fp)
122 _IO_FILE *fp;
124 struct _IO_codecvt *cd;
125 enum __codecvt_result status;
126 _IO_ssize_t count;
127 int tries;
128 const char *read_ptr_copy;
130 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
132 fp->_flags |= _IO_ERR_SEEN;
133 __set_errno (EBADF);
134 return WEOF;
136 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
137 return *fp->_wide_data->_IO_read_ptr;
139 cd = fp->_codecvt;
141 /* Maybe there is something left in the external buffer. */
142 if (fp->_IO_read_ptr < fp->_IO_read_end)
144 /* There is more in the external. Convert it. */
145 const char *read_stop = (const char *) fp->_IO_read_ptr;
147 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
148 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
149 fp->_wide_data->_IO_buf_base;
150 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
151 fp->_IO_read_ptr, fp->_IO_read_end,
152 &read_stop,
153 fp->_wide_data->_IO_read_ptr,
154 fp->_wide_data->_IO_buf_end,
155 &fp->_wide_data->_IO_read_end);
157 fp->_IO_read_ptr = (char *) read_stop;
159 /* If we managed to generate some text return the next character. */
160 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
161 return *fp->_wide_data->_IO_read_ptr;
163 if (status == __codecvt_error)
165 __set_errno (EILSEQ);
166 fp->_flags |= _IO_ERR_SEEN;
167 return WEOF;
170 /* Move the remaining content of the read buffer to the beginning. */
171 memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
172 fp->_IO_read_end - fp->_IO_read_ptr);
173 fp->_IO_read_end = (fp->_IO_buf_base
174 + (fp->_IO_read_end - fp->_IO_read_ptr));
175 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
177 else
178 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
179 fp->_IO_buf_base;
181 if (fp->_IO_buf_base == NULL)
183 /* Maybe we already have a push back pointer. */
184 if (fp->_IO_save_base != NULL)
186 free (fp->_IO_save_base);
187 fp->_flags &= ~_IO_IN_BACKUP;
189 INTUSE(_IO_doallocbuf) (fp);
191 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
192 fp->_IO_buf_base;
195 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
196 fp->_IO_buf_base;
198 if (fp->_wide_data->_IO_buf_base == NULL)
200 /* Maybe we already have a push back pointer. */
201 if (fp->_wide_data->_IO_save_base != NULL)
203 free (fp->_wide_data->_IO_save_base);
204 fp->_flags &= ~_IO_IN_BACKUP;
206 INTUSE(_IO_wdoallocbuf) (fp);
209 /* Flush all line buffered files before reading. */
210 /* FIXME This can/should be moved to genops ?? */
211 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
213 #if 0
214 INTUSE(_IO_flush_all_linebuffered) ();
215 #else
216 /* We used to flush all line-buffered stream. This really isn't
217 required by any standard. My recollection is that
218 traditional Unix systems did this for stdout. stderr better
219 not be line buffered. So we do just that here
220 explicitly. --drepper */
221 _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile,
222 _IO_stdout);
223 _IO_flockfile (_IO_stdout);
225 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
226 == (_IO_LINKED | _IO_LINE_BUF))
227 _IO_OVERFLOW (_IO_stdout, EOF);
229 _IO_funlockfile (_IO_stdout);
230 _IO_cleanup_region_end (0);
231 #endif
234 INTUSE(_IO_switch_to_get_mode) (fp);
236 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
237 fp->_wide_data->_IO_buf_base;
238 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
239 fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
240 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
242 tries = 0;
243 again:
244 count = _IO_SYSREAD (fp, fp->_IO_read_end,
245 fp->_IO_buf_end - fp->_IO_read_end);
246 if (count <= 0)
248 if (count == 0 && tries == 0)
249 fp->_flags |= _IO_EOF_SEEN;
250 else
251 fp->_flags |= _IO_ERR_SEEN, count = 0;
253 fp->_IO_read_end += count;
254 if (count == 0)
256 if (tries != 0)
257 /* There are some bytes in the external buffer but they don't
258 convert to anything. */
259 __set_errno (EILSEQ);
260 return WEOF;
262 if (fp->_offset != _IO_pos_BAD)
263 _IO_pos_adjust (fp->_offset, count);
265 /* Now convert the read input. */
266 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
267 fp->_IO_read_base = fp->_IO_read_ptr;
268 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
269 fp->_IO_read_ptr, fp->_IO_read_end,
270 &read_ptr_copy,
271 fp->_wide_data->_IO_read_end,
272 fp->_wide_data->_IO_buf_end,
273 &fp->_wide_data->_IO_read_end);
275 fp->_IO_read_ptr = (char *) read_ptr_copy;
276 if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
278 if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
280 __set_errno (EILSEQ);
281 fp->_flags |= _IO_ERR_SEEN;
282 return WEOF;
285 /* The read bytes make no complete character. Try reading again. */
286 assert (status == __codecvt_partial);
287 ++tries;
288 goto again;
291 return *fp->_wide_data->_IO_read_ptr;
293 INTDEF(_IO_wfile_underflow)
296 #ifdef HAVE_MMAP
297 static wint_t
298 _IO_wfile_underflow_mmap (_IO_FILE *fp)
300 struct _IO_codecvt *cd;
301 enum __codecvt_result status;
302 const char *read_stop;
304 if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
306 fp->_flags |= _IO_ERR_SEEN;
307 __set_errno (EBADF);
308 return WEOF;
310 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
311 return *fp->_wide_data->_IO_read_ptr;
313 cd = fp->_codecvt;
315 /* Maybe there is something left in the external buffer. */
316 if (fp->_IO_read_ptr >= fp->_IO_read_end
317 /* No. But maybe the read buffer is not fully set up. */
318 && _IO_file_underflow_mmap (fp) == EOF)
319 /* Nothing available. _IO_file_underflow_mmap has set the EOF or error
320 flags as appropriate. */
321 return WEOF;
323 /* There is more in the external. Convert it. */
324 read_stop = (const char *) fp->_IO_read_ptr;
326 if (fp->_wide_data->_IO_buf_base == NULL)
328 /* Maybe we already have a push back pointer. */
329 if (fp->_wide_data->_IO_save_base != NULL)
331 free (fp->_wide_data->_IO_save_base);
332 fp->_flags &= ~_IO_IN_BACKUP;
334 INTUSE(_IO_wdoallocbuf) (fp);
337 fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
338 fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
339 fp->_wide_data->_IO_buf_base;
340 status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
341 fp->_IO_read_ptr, fp->_IO_read_end,
342 &read_stop,
343 fp->_wide_data->_IO_read_ptr,
344 fp->_wide_data->_IO_buf_end,
345 &fp->_wide_data->_IO_read_end);
347 fp->_IO_read_ptr = (char *) read_stop;
349 /* If we managed to generate some text return the next character. */
350 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
351 return *fp->_wide_data->_IO_read_ptr;
353 /* There is some garbage at the end of the file. */
354 __set_errno (EILSEQ);
355 fp->_flags |= _IO_ERR_SEEN;
356 return WEOF;
359 static wint_t
360 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
362 /* This is the first read attempt. Doing the underflow will choose mmap
363 or vanilla operations and then punt to the chosen underflow routine.
364 Then we can punt to ours. */
365 if (_IO_file_underflow_maybe_mmap (fp) == EOF)
366 return WEOF;
368 return _IO_WUNDERFLOW (fp);
370 #endif
373 wint_t
374 _IO_wfile_overflow (f, wch)
375 _IO_FILE *f;
376 wint_t wch;
378 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
380 f->_flags |= _IO_ERR_SEEN;
381 __set_errno (EBADF);
382 return WEOF;
384 /* If currently reading or no buffer allocated. */
385 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
387 /* Allocate a buffer if needed. */
388 if (f->_wide_data->_IO_write_base == 0)
390 INTUSE(_IO_wdoallocbuf) (f);
391 _IO_wsetg (f, f->_wide_data->_IO_buf_base,
392 f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
394 if (f->_IO_write_base == NULL)
396 INTUSE(_IO_doallocbuf) (f);
397 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
400 else
402 /* Otherwise must be currently reading. If _IO_read_ptr
403 (and hence also _IO_read_end) is at the buffer end,
404 logically slide the buffer forwards one block (by setting
405 the read pointers to all point at the beginning of the
406 block). This makes room for subsequent output.
407 Otherwise, set the read pointers to _IO_read_end (leaving
408 that alone, so it can continue to correspond to the
409 external position). */
410 if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
412 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
413 f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
414 f->_wide_data->_IO_buf_base;
417 f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
418 f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
419 f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
420 f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
421 f->_wide_data->_IO_read_end;
423 f->_IO_write_ptr = f->_IO_read_ptr;
424 f->_IO_write_base = f->_IO_write_ptr;
425 f->_IO_write_end = f->_IO_buf_end;
426 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
428 f->_flags |= _IO_CURRENTLY_PUTTING;
429 if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
430 f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
432 if (wch == WEOF)
433 return _IO_do_flush (f);
434 if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
435 /* Buffer is really full */
436 if (_IO_do_flush (f) == EOF)
437 return WEOF;
438 *f->_wide_data->_IO_write_ptr++ = wch;
439 if ((f->_flags & _IO_UNBUFFERED)
440 || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
441 if (_IO_do_flush (f) == EOF)
442 return WEOF;
443 return wch;
445 INTDEF(_IO_wfile_overflow)
447 wint_t
448 _IO_wfile_sync (fp)
449 _IO_FILE *fp;
451 _IO_ssize_t delta;
452 wint_t retval = 0;
454 /* char* ptr = cur_ptr(); */
455 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
456 if (_IO_do_flush (fp))
457 return WEOF;
458 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
459 if (delta != 0)
461 /* We have to find out how many bytes we have to go back in the
462 external buffer. */
463 struct _IO_codecvt *cv = fp->_codecvt;
464 _IO_off64_t new_pos;
466 int clen = (*cv->__codecvt_do_encoding) (cv);
468 if (clen > 0)
469 /* It is easy, a fixed number of input bytes are used for each
470 wide character. */
471 delta *= clen;
472 else
474 /* We have to find out the hard way how much to back off.
475 To do this we determine how much input we needed to
476 generate the wide characters up to the current reading
477 position. */
478 int nread;
480 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
481 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
482 fp->_IO_read_base,
483 fp->_IO_read_end, delta);
484 fp->_IO_read_ptr = fp->_IO_read_base + nread;
485 delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
488 new_pos = _IO_SYSSEEK (fp, delta, 1);
489 if (new_pos != (_IO_off64_t) EOF)
491 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
492 fp->_IO_read_end = fp->_IO_read_ptr;
494 #ifdef ESPIPE
495 else if (errno == ESPIPE)
496 ; /* Ignore error from unseekable devices. */
497 #endif
498 else
499 retval = WEOF;
501 if (retval != WEOF)
502 fp->_offset = _IO_pos_BAD;
503 /* FIXME: Cleanup - can this be shared? */
504 /* setg(base(), ptr, ptr); */
505 return retval;
507 INTDEF(_IO_wfile_sync)
509 _IO_off64_t
510 _IO_wfile_seekoff (fp, offset, dir, mode)
511 _IO_FILE *fp;
512 _IO_off64_t offset;
513 int dir;
514 int mode;
516 _IO_off64_t result;
517 _IO_off64_t delta, new_offset;
518 long int count;
519 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
520 offset of the underlying file must be exact. */
521 int must_be_exact = ((fp->_wide_data->_IO_read_base
522 == fp->_wide_data->_IO_read_end)
523 && (fp->_wide_data->_IO_write_base
524 == fp->_wide_data->_IO_write_ptr));
526 if (mode == 0)
528 /* XXX For wide stream with backup store it is not very
529 reasonable to determine the offset. The pushed-back
530 character might require a state change and we need not be
531 able to compute the initial state by reverse transformation
532 since there is no guarantee of symmetry. So we don't even
533 try and return an error. */
534 if (_IO_in_backup (fp))
536 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
538 __set_errno (EINVAL);
539 return -1;
542 /* There is no more data in the backup buffer. We can
543 switch back. */
544 INTUSE(_IO_switch_to_main_wget_area) (fp);
547 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
550 /* Flush unwritten characters.
551 (This may do an unneeded write if we seek within the buffer.
552 But to be able to switch to reading, we would need to set
553 egptr to ptr. That can't be done in the current design,
554 which assumes file_ptr() is eGptr. Anyway, since we probably
555 end up flushing when we close(), it doesn't make much difference.)
556 FIXME: simulate mem-mapped files. */
558 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
559 || _IO_in_put_mode (fp))
560 if (INTUSE(_IO_switch_to_wget_mode) (fp))
561 return WEOF;
563 if (fp->_wide_data->_IO_buf_base == NULL)
565 /* It could be that we already have a pushback buffer. */
566 if (fp->_wide_data->_IO_read_base != NULL)
568 free (fp->_wide_data->_IO_read_base);
569 fp->_flags &= ~_IO_IN_BACKUP;
571 INTUSE(_IO_doallocbuf) (fp);
572 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
573 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
574 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
575 fp->_wide_data->_IO_buf_base);
576 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
577 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
580 switch (dir)
582 struct _IO_codecvt *cv;
583 int clen;
585 case _IO_seek_cur:
586 /* Adjust for read-ahead (bytes is buffer). To do this we must
587 find out which position in the external buffer corresponds to
588 the current position in the internal buffer. */
589 cv = fp->_codecvt;
590 clen = (*cv->__codecvt_do_encoding) (cv);
592 if (clen > 0)
593 offset -= (fp->_wide_data->_IO_read_end
594 - fp->_wide_data->_IO_read_ptr) * clen;
595 else
597 int nread;
599 delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
600 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
601 nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
602 fp->_IO_read_base,
603 fp->_IO_read_end, delta);
604 fp->_IO_read_ptr = fp->_IO_read_base + nread;
605 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
606 offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
609 if (fp->_offset == _IO_pos_BAD)
610 goto dumb;
611 /* Make offset absolute, assuming current pointer is file_ptr(). */
612 offset += fp->_offset;
614 dir = _IO_seek_set;
615 break;
616 case _IO_seek_set:
617 break;
618 case _IO_seek_end:
620 struct _G_stat64 st;
621 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
623 offset += st.st_size;
624 dir = _IO_seek_set;
626 else
627 goto dumb;
630 /* At this point, dir==_IO_seek_set. */
632 /* If we are only interested in the current position we've found it now. */
633 if (mode == 0)
634 return offset;
636 /* If destination is within current buffer, optimize: */
637 if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
638 && !_IO_in_backup (fp))
640 /* Offset relative to start of main get area. */
641 _IO_off64_t rel_offset = (offset - fp->_offset
642 + (fp->_IO_read_end - fp->_IO_buf_base));
643 if (rel_offset >= 0)
645 #if 0
646 if (_IO_in_backup (fp))
647 _IO_switch_to_main_get_area (fp);
648 #endif
649 if (rel_offset <= fp->_IO_read_end - fp->_IO_buf_base)
651 enum __codecvt_result status;
652 struct _IO_codecvt *cd = fp->_codecvt;
653 const char *read_ptr_copy;
655 fp->_IO_read_ptr = fp->_IO_read_base + rel_offset;
656 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
658 /* Now set the pointer for the internal buffer. This
659 might be an iterative process. Though the read
660 pointer is somewhere in the current external buffer
661 this does not mean we can convert this whole buffer
662 at once fitting in the internal buffer. */
663 fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
664 read_ptr_copy = fp->_IO_read_base;
665 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
668 wchar_t buffer[1024];
669 wchar_t *ignore;
670 status = (*cd->__codecvt_do_in) (cd,
671 &fp->_wide_data->_IO_state,
672 read_ptr_copy,
673 fp->_IO_read_ptr,
674 &read_ptr_copy,
675 buffer,
676 buffer
677 + (sizeof (buffer)
678 / sizeof (buffer[0])),
679 &ignore);
680 if (status != __codecvt_ok && status != __codecvt_partial)
682 fp->_flags |= _IO_ERR_SEEN;
683 goto dumb;
686 while (read_ptr_copy != fp->_IO_read_ptr);
688 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
690 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
691 goto resync;
693 #ifdef TODO
694 /* If we have streammarkers, seek forward by reading ahead. */
695 if (_IO_have_markers (fp))
697 int to_skip = rel_offset
698 - (fp->_IO_read_ptr - fp->_IO_read_base);
699 if (ignore (to_skip) != to_skip)
700 goto dumb;
701 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
702 goto resync;
704 #endif
706 #ifdef TODO
707 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
709 if (!_IO_in_backup (fp))
710 _IO_switch_to_backup_area (fp);
711 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
712 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
713 goto resync;
715 #endif
718 #ifdef TODO
719 INTUSE(_IO_unsave_markers) (fp);
720 #endif
722 if (fp->_flags & _IO_NO_READS)
723 goto dumb;
725 /* Try to seek to a block boundary, to improve kernel page management. */
726 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
727 delta = offset - new_offset;
728 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
730 new_offset = offset;
731 delta = 0;
733 result = _IO_SYSSEEK (fp, new_offset, 0);
734 if (result < 0)
735 return EOF;
736 if (delta == 0)
737 count = 0;
738 else
740 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
741 (must_be_exact
742 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
743 if (count < delta)
745 /* We weren't allowed to read, but try to seek the remainder. */
746 offset = count == EOF ? delta : delta-count;
747 dir = _IO_seek_cur;
748 goto dumb;
751 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
752 fp->_IO_buf_base + count);
753 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
754 fp->_offset = result + count;
755 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
756 return offset;
757 dumb:
759 INTUSE(_IO_unsave_markers) (fp);
760 result = _IO_SYSSEEK (fp, offset, dir);
761 if (result != EOF)
763 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
764 fp->_offset = result;
765 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
766 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
767 _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
768 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
769 _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
770 fp->_wide_data->_IO_buf_base);
772 return result;
774 resync:
775 /* We need to do it since it is possible that the file offset in
776 the kernel may be changed behind our back. It may happen when
777 we fopen a file and then do a fork. One process may access the
778 the file and the kernel file offset will be changed. */
779 if (fp->_offset >= 0)
780 _IO_SYSSEEK (fp, fp->_offset, 0);
782 return offset;
784 INTDEF(_IO_wfile_seekoff)
787 _IO_size_t
788 _IO_wfile_xsputn (f, data, n)
789 _IO_FILE *f;
790 const void *data;
791 _IO_size_t n;
793 register const wchar_t *s = (const wchar_t *) data;
794 _IO_size_t to_do = n;
795 int must_flush = 0;
796 _IO_size_t count;
798 if (n <= 0)
799 return 0;
800 /* This is an optimized implementation.
801 If the amount to be written straddles a block boundary
802 (or the filebuf is unbuffered), use sys_write directly. */
804 /* First figure out how much space is available in the buffer. */
805 count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
806 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
808 count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
809 if (count >= n)
811 register const wchar_t *p;
812 for (p = s + n; p > s; )
814 if (*--p == L'\n')
816 count = p - s + 1;
817 must_flush = 1;
818 break;
823 /* Then fill the buffer. */
824 if (count > 0)
826 if (count > to_do)
827 count = to_do;
828 if (count > 20)
830 #ifdef _LIBC
831 f->_wide_data->_IO_write_ptr =
832 __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
833 #else
834 wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
835 f->_wide_data->_IO_write_ptr += count;
836 #endif
837 s += count;
839 else
841 register wchar_t *p = f->_wide_data->_IO_write_ptr;
842 register int i = (int) count;
843 while (--i >= 0)
844 *p++ = *s++;
845 f->_wide_data->_IO_write_ptr = p;
847 to_do -= count;
849 if (to_do > 0)
850 to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);
851 if (must_flush
852 && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
853 INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base,
854 f->_wide_data->_IO_write_ptr
855 - f->_wide_data->_IO_write_base);
857 return n - to_do;
859 INTDEF(_IO_wfile_xsputn)
862 struct _IO_jump_t _IO_wfile_jumps =
864 JUMP_INIT_DUMMY,
865 JUMP_INIT(finish, _IO_new_file_finish),
866 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
867 JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)),
868 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
869 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
870 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
871 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
872 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
873 JUMP_INIT(seekpos, _IO_default_seekpos),
874 JUMP_INIT(setbuf, _IO_new_file_setbuf),
875 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
876 JUMP_INIT(doallocate, _IO_wfile_doallocate),
877 JUMP_INIT(read, INTUSE(_IO_file_read)),
878 JUMP_INIT(write, _IO_new_file_write),
879 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
880 JUMP_INIT(close, INTUSE(_IO_file_close)),
881 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
882 JUMP_INIT(showmanyc, _IO_default_showmanyc),
883 JUMP_INIT(imbue, _IO_default_imbue)
885 INTVARDEF(_IO_wfile_jumps)
888 #ifdef HAVE_MMAP
889 struct _IO_jump_t _IO_wfile_jumps_mmap =
891 JUMP_INIT_DUMMY,
892 JUMP_INIT(finish, _IO_new_file_finish),
893 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
894 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
895 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
896 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
897 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
898 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
899 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
900 JUMP_INIT(seekpos, _IO_default_seekpos),
901 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
902 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
903 JUMP_INIT(doallocate, _IO_wfile_doallocate),
904 JUMP_INIT(read, INTUSE(_IO_file_read)),
905 JUMP_INIT(write, _IO_new_file_write),
906 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
907 JUMP_INIT(close, _IO_file_close_mmap),
908 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
909 JUMP_INIT(showmanyc, _IO_default_showmanyc),
910 JUMP_INIT(imbue, _IO_default_imbue)
913 struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
915 JUMP_INIT_DUMMY,
916 JUMP_INIT(finish, _IO_new_file_finish),
917 JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
918 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
919 JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
920 JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
921 JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
922 JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
923 JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
924 JUMP_INIT(seekpos, _IO_default_seekpos),
925 JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
926 JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
927 JUMP_INIT(doallocate, _IO_wfile_doallocate),
928 JUMP_INIT(read, INTUSE(_IO_file_read)),
929 JUMP_INIT(write, _IO_new_file_write),
930 JUMP_INIT(seek, INTUSE(_IO_file_seek)),
931 JUMP_INIT(close, INTUSE(_IO_file_close)),
932 JUMP_INIT(stat, INTUSE(_IO_file_stat)),
933 JUMP_INIT(showmanyc, _IO_default_showmanyc),
934 JUMP_INIT(imbue, _IO_default_imbue)
936 #endif