Avoid dup3 PLT usage.
[platform/upstream/glibc.git] / libio / wfileops.c
1 /* Copyright (C) 1993,1995,1997-2004,2006,2009,2011 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>.
5
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.
10
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.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.
19
20    As a special exception, if you link the code in this file with
21    files compiled with a GNU compiler to produce an executable,
22    that does not cause the resulting executable to be covered by
23    the GNU Lesser General Public License.  This exception does not
24    however invalidate any other reasons why the executable file
25    might be covered by the GNU Lesser General Public License.
26    This exception applies to code released by its copyright holders
27    in files containing the exception.  */
28
29 #include <assert.h>
30 #include <libioP.h>
31 #include <wchar.h>
32 #include <gconv.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36
37 #ifndef _LIBC
38 # define _IO_new_do_write _IO_do_write
39 # define _IO_new_file_attach _IO_file_attach
40 # define _IO_new_file_close_it _IO_file_close_it
41 # define _IO_new_file_finish _IO_file_finish
42 # define _IO_new_file_fopen _IO_file_fopen
43 # define _IO_new_file_init _IO_file_init
44 # define _IO_new_file_setbuf _IO_file_setbuf
45 # define _IO_new_file_sync _IO_file_sync
46 # define _IO_new_file_overflow _IO_file_overflow
47 # define _IO_new_file_seekoff _IO_file_seekoff
48 # define _IO_new_file_underflow _IO_file_underflow
49 # define _IO_new_file_write _IO_file_write
50 # define _IO_new_file_xsputn _IO_file_xsputn
51 #endif
52
53
54 /* Convert TO_DO wide character from DATA to FP.
55    Then mark FP as having empty buffers. */
56 int
57 _IO_wdo_write (fp, data, to_do)
58      _IO_FILE *fp;
59      const wchar_t *data;
60      _IO_size_t to_do;
61 {
62   struct _IO_codecvt *cc = fp->_codecvt;
63
64   if (to_do > 0)
65     {
66       if (fp->_IO_write_end == fp->_IO_write_ptr
67           && fp->_IO_write_end != fp->_IO_write_base)
68         {
69           if (_IO_new_do_write (fp, fp->_IO_write_base,
70                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
71             return WEOF;
72         }
73
74       do
75         {
76           enum __codecvt_result result;
77           const wchar_t *new_data;
78
79           /* Now convert from the internal format into the external buffer.  */
80           result = (*cc->__codecvt_do_out) (cc, &fp->_wide_data->_IO_state,
81                                             data, data + to_do, &new_data,
82                                             fp->_IO_write_ptr,
83                                             fp->_IO_buf_end,
84                                             &fp->_IO_write_ptr);
85
86           /* Write out what we produced so far.  */
87           if (_IO_new_do_write (fp, fp->_IO_write_base,
88                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
89             /* Something went wrong.  */
90             return WEOF;
91
92           to_do -= new_data - data;
93
94           /* Next see whether we had problems during the conversion.  If yes,
95              we cannot go on.  */
96           if (result != __codecvt_ok
97               && (result != __codecvt_partial || new_data - data == 0))
98             break;
99
100           data = new_data;
101         }
102       while (to_do > 0);
103     }
104
105   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
106              fp->_wide_data->_IO_buf_base);
107   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
108     = fp->_wide_data->_IO_buf_base;
109   fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
110                                    ? fp->_wide_data->_IO_buf_base
111                                    : fp->_wide_data->_IO_buf_end);
112
113   return to_do == 0 ? 0 : WEOF;
114 }
115 INTDEF(_IO_wdo_write)
116
117
118 wint_t
119 _IO_wfile_underflow (fp)
120      _IO_FILE *fp;
121 {
122   struct _IO_codecvt *cd;
123   enum __codecvt_result status;
124   _IO_ssize_t count;
125
126   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
127     {
128       fp->_flags |= _IO_ERR_SEEN;
129       __set_errno (EBADF);
130       return WEOF;
131     }
132   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
133     return *fp->_wide_data->_IO_read_ptr;
134
135   cd = fp->_codecvt;
136
137   /* Maybe there is something left in the external buffer.  */
138   if (fp->_IO_read_ptr < fp->_IO_read_end)
139     {
140       /* There is more in the external.  Convert it.  */
141       const char *read_stop = (const char *) fp->_IO_read_ptr;
142
143       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
144       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
145         fp->_wide_data->_IO_buf_base;
146       status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
147                                        fp->_IO_read_ptr, fp->_IO_read_end,
148                                        &read_stop,
149                                        fp->_wide_data->_IO_read_ptr,
150                                        fp->_wide_data->_IO_buf_end,
151                                        &fp->_wide_data->_IO_read_end);
152
153       fp->_IO_read_base = fp->_IO_read_ptr;
154       fp->_IO_read_ptr = (char *) read_stop;
155
156       /* If we managed to generate some text return the next character.  */
157       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
158         return *fp->_wide_data->_IO_read_ptr;
159
160       if (status == __codecvt_error)
161         {
162           __set_errno (EILSEQ);
163           fp->_flags |= _IO_ERR_SEEN;
164           return WEOF;
165         }
166
167       /* Move the remaining content of the read buffer to the beginning.  */
168       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
169                fp->_IO_read_end - fp->_IO_read_ptr);
170       fp->_IO_read_end = (fp->_IO_buf_base
171                           + (fp->_IO_read_end - fp->_IO_read_ptr));
172       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
173     }
174   else
175     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
176       fp->_IO_buf_base;
177
178   if (fp->_IO_buf_base == NULL)
179     {
180       /* Maybe we already have a push back pointer.  */
181       if (fp->_IO_save_base != NULL)
182         {
183           free (fp->_IO_save_base);
184           fp->_flags &= ~_IO_IN_BACKUP;
185         }
186       INTUSE(_IO_doallocbuf) (fp);
187
188       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
189         fp->_IO_buf_base;
190     }
191
192   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
193     fp->_IO_buf_base;
194
195   if (fp->_wide_data->_IO_buf_base == NULL)
196     {
197       /* Maybe we already have a push back pointer.  */
198       if (fp->_wide_data->_IO_save_base != NULL)
199         {
200           free (fp->_wide_data->_IO_save_base);
201           fp->_flags &= ~_IO_IN_BACKUP;
202         }
203       INTUSE(_IO_wdoallocbuf) (fp);
204     }
205
206   /* Flush all line buffered files before reading. */
207   /* FIXME This can/should be moved to genops ?? */
208   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
209     {
210 #if 0
211       INTUSE(_IO_flush_all_linebuffered) ();
212 #else
213       /* We used to flush all line-buffered stream.  This really isn't
214          required by any standard.  My recollection is that
215          traditional Unix systems did this for stdout.  stderr better
216          not be line buffered.  So we do just that here
217          explicitly.  --drepper */
218       _IO_acquire_lock (_IO_stdout);
219
220       if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
221           == (_IO_LINKED | _IO_LINE_BUF))
222         _IO_OVERFLOW (_IO_stdout, EOF);
223
224       _IO_release_lock (_IO_stdout);
225 #endif
226     }
227
228   INTUSE(_IO_switch_to_get_mode) (fp);
229
230   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
231     fp->_wide_data->_IO_buf_base;
232   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
233   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
234     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
235
236   const char *read_ptr_copy;
237   char accbuf[MB_LEN_MAX];
238   size_t naccbuf = 0;
239  again:
240   count = _IO_SYSREAD (fp, fp->_IO_read_end,
241                        fp->_IO_buf_end - fp->_IO_read_end);
242   if (count <= 0)
243     {
244       if (count == 0 && naccbuf == 0)
245         fp->_flags |= _IO_EOF_SEEN;
246       else
247         fp->_flags |= _IO_ERR_SEEN, count = 0;
248     }
249   fp->_IO_read_end += count;
250   if (count == 0)
251     {
252       if (naccbuf != 0)
253         /* There are some bytes in the external buffer but they don't
254            convert to anything.  */
255         __set_errno (EILSEQ);
256       return WEOF;
257     }
258   if (fp->_offset != _IO_pos_BAD)
259     _IO_pos_adjust (fp->_offset, count);
260
261   /* Now convert the read input.  */
262   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
263   fp->_IO_read_base = fp->_IO_read_ptr;
264   const char *from = fp->_IO_read_ptr;
265   const char *to = fp->_IO_read_end;
266   size_t to_copy = count;
267   if (__builtin_expect (naccbuf != 0, 0))
268     {
269       to_copy = MIN (sizeof (accbuf) - naccbuf, count);
270       to = __mempcpy (&accbuf[naccbuf], from, to_copy);
271       naccbuf += to_copy;
272       from = accbuf;
273     }
274   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
275                                    from, to, &read_ptr_copy,
276                                    fp->_wide_data->_IO_read_end,
277                                    fp->_wide_data->_IO_buf_end,
278                                    &fp->_wide_data->_IO_read_end);
279
280   if (__builtin_expect (naccbuf != 0, 0))
281     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
282   else
283     fp->_IO_read_ptr = (char *) read_ptr_copy;
284   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
285     {
286       if (status == __codecvt_error)
287         {
288         out_eilseq:
289           __set_errno (EILSEQ);
290           fp->_flags |= _IO_ERR_SEEN;
291           return WEOF;
292         }
293
294       /* The read bytes make no complete character.  Try reading again.  */
295       assert (status == __codecvt_partial);
296
297       if (naccbuf == 0)
298         {
299           if (fp->_IO_read_base < fp->_IO_read_ptr)
300             {
301               /* Partially used the buffer for some input data that
302                  produces no output.  */
303               size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
304               memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
305               fp->_IO_read_ptr = fp->_IO_read_base;
306               fp->_IO_read_end -= avail;
307               goto again;
308             }
309           naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
310           if (naccbuf >= sizeof (accbuf))
311             goto out_eilseq;
312
313           memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
314         }
315       else
316         {
317           size_t used = read_ptr_copy - accbuf;
318           if (used > 0)
319             {
320               memmove (accbuf, read_ptr_copy, naccbuf - used);
321               naccbuf -= used;
322             }
323
324           if (naccbuf == sizeof (accbuf))
325             goto out_eilseq;
326         }
327
328       fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
329
330       goto again;
331     }
332
333   return *fp->_wide_data->_IO_read_ptr;
334 }
335 INTDEF(_IO_wfile_underflow)
336
337
338 static wint_t
339 _IO_wfile_underflow_mmap (_IO_FILE *fp)
340 {
341   struct _IO_codecvt *cd;
342   const char *read_stop;
343
344   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
345     {
346       fp->_flags |= _IO_ERR_SEEN;
347       __set_errno (EBADF);
348       return WEOF;
349     }
350   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
351     return *fp->_wide_data->_IO_read_ptr;
352
353   cd = fp->_codecvt;
354
355   /* Maybe there is something left in the external buffer.  */
356   if (fp->_IO_read_ptr >= fp->_IO_read_end
357       /* No.  But maybe the read buffer is not fully set up.  */
358       && _IO_file_underflow_mmap (fp) == EOF)
359     /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
360        flags as appropriate.  */
361     return WEOF;
362
363   /* There is more in the external.  Convert it.  */
364   read_stop = (const char *) fp->_IO_read_ptr;
365
366   if (fp->_wide_data->_IO_buf_base == NULL)
367     {
368       /* Maybe we already have a push back pointer.  */
369       if (fp->_wide_data->_IO_save_base != NULL)
370         {
371           free (fp->_wide_data->_IO_save_base);
372           fp->_flags &= ~_IO_IN_BACKUP;
373         }
374       INTUSE(_IO_wdoallocbuf) (fp);
375     }
376
377   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
378   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
379     fp->_wide_data->_IO_buf_base;
380   (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
381                           fp->_IO_read_ptr, fp->_IO_read_end,
382                           &read_stop,
383                           fp->_wide_data->_IO_read_ptr,
384                           fp->_wide_data->_IO_buf_end,
385                           &fp->_wide_data->_IO_read_end);
386
387   fp->_IO_read_ptr = (char *) read_stop;
388
389   /* If we managed to generate some text return the next character.  */
390   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
391     return *fp->_wide_data->_IO_read_ptr;
392
393   /* There is some garbage at the end of the file.  */
394   __set_errno (EILSEQ);
395   fp->_flags |= _IO_ERR_SEEN;
396   return WEOF;
397 }
398
399 static wint_t
400 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
401 {
402   /* This is the first read attempt.  Doing the underflow will choose mmap
403      or vanilla operations and then punt to the chosen underflow routine.
404      Then we can punt to ours.  */
405   if (_IO_file_underflow_maybe_mmap (fp) == EOF)
406     return WEOF;
407
408   return _IO_WUNDERFLOW (fp);
409 }
410
411
412 wint_t
413 _IO_wfile_overflow (f, wch)
414      _IO_FILE *f;
415      wint_t wch;
416 {
417   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
418     {
419       f->_flags |= _IO_ERR_SEEN;
420       __set_errno (EBADF);
421       return WEOF;
422     }
423   /* If currently reading or no buffer allocated. */
424   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
425     {
426       /* Allocate a buffer if needed. */
427       if (f->_wide_data->_IO_write_base == 0)
428         {
429           INTUSE(_IO_wdoallocbuf) (f);
430           _IO_wsetg (f, f->_wide_data->_IO_buf_base,
431                      f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
432
433           if (f->_IO_write_base == NULL)
434             {
435               INTUSE(_IO_doallocbuf) (f);
436               _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
437             }
438         }
439       else
440         {
441           /* Otherwise must be currently reading.  If _IO_read_ptr
442              (and hence also _IO_read_end) is at the buffer end,
443              logically slide the buffer forwards one block (by setting
444              the read pointers to all point at the beginning of the
445              block).  This makes room for subsequent output.
446              Otherwise, set the read pointers to _IO_read_end (leaving
447              that alone, so it can continue to correspond to the
448              external position). */
449           if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
450             {
451               f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
452               f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
453                 f->_wide_data->_IO_buf_base;
454             }
455         }
456       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
457       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
458       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
459       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
460         f->_wide_data->_IO_read_end;
461
462       f->_IO_write_ptr = f->_IO_read_ptr;
463       f->_IO_write_base = f->_IO_write_ptr;
464       f->_IO_write_end = f->_IO_buf_end;
465       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
466
467       f->_flags |= _IO_CURRENTLY_PUTTING;
468       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
469         f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
470     }
471   if (wch == WEOF)
472     return _IO_do_flush (f);
473   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
474     /* Buffer is really full */
475     if (_IO_do_flush (f) == EOF)
476       return WEOF;
477   *f->_wide_data->_IO_write_ptr++ = wch;
478   if ((f->_flags & _IO_UNBUFFERED)
479       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
480     if (_IO_do_flush (f) == EOF)
481       return WEOF;
482   return wch;
483 }
484 INTDEF(_IO_wfile_overflow)
485
486 wint_t
487 _IO_wfile_sync (fp)
488      _IO_FILE *fp;
489 {
490   _IO_ssize_t delta;
491   wint_t retval = 0;
492
493   /*    char* ptr = cur_ptr(); */
494   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
495     if (_IO_do_flush (fp))
496       return WEOF;
497   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
498   if (delta != 0)
499     {
500       /* We have to find out how many bytes we have to go back in the
501          external buffer.  */
502       struct _IO_codecvt *cv = fp->_codecvt;
503       _IO_off64_t new_pos;
504
505       int clen = (*cv->__codecvt_do_encoding) (cv);
506
507       if (clen > 0)
508         /* It is easy, a fixed number of input bytes are used for each
509            wide character.  */
510         delta *= clen;
511       else
512         {
513           /* We have to find out the hard way how much to back off.
514              To do this we determine how much input we needed to
515              generate the wide characters up to the current reading
516              position.  */
517           int nread;
518
519           fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
520           nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
521                                               fp->_IO_read_base,
522                                               fp->_IO_read_end, delta);
523           fp->_IO_read_ptr = fp->_IO_read_base + nread;
524           delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
525         }
526
527       new_pos = _IO_SYSSEEK (fp, delta, 1);
528       if (new_pos != (_IO_off64_t) EOF)
529         {
530           fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
531           fp->_IO_read_end = fp->_IO_read_ptr;
532         }
533 #ifdef ESPIPE
534       else if (errno == ESPIPE)
535         ; /* Ignore error from unseekable devices. */
536 #endif
537       else
538         retval = WEOF;
539     }
540   if (retval != WEOF)
541     fp->_offset = _IO_pos_BAD;
542   /* FIXME: Cleanup - can this be shared? */
543   /*    setg(base(), ptr, ptr); */
544   return retval;
545 }
546 INTDEF(_IO_wfile_sync)
547
548 _IO_off64_t
549 _IO_wfile_seekoff (fp, offset, dir, mode)
550      _IO_FILE *fp;
551      _IO_off64_t offset;
552      int dir;
553      int mode;
554 {
555   _IO_off64_t result;
556   _IO_off64_t delta, new_offset;
557   long int count;
558   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
559      offset of the underlying file must be exact.  */
560   int must_be_exact = ((fp->_wide_data->_IO_read_base
561                         == fp->_wide_data->_IO_read_end)
562                        && (fp->_wide_data->_IO_write_base
563                            == fp->_wide_data->_IO_write_ptr));
564
565   if (mode == 0)
566     {
567       /* XXX For wide stream with backup store it is not very
568          reasonable to determine the offset.  The pushed-back
569          character might require a state change and we need not be
570          able to compute the initial state by reverse transformation
571          since there is no guarantee of symmetry.  So we don't even
572          try and return an error.  */
573       if (_IO_in_backup (fp))
574         {
575           if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
576             {
577               __set_errno (EINVAL);
578               return -1;
579             }
580
581           /* There is no more data in the backup buffer.  We can
582              switch back.  */
583           INTUSE(_IO_switch_to_main_wget_area) (fp);
584         }
585
586       dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
587     }
588
589   /* Flush unwritten characters.
590      (This may do an unneeded write if we seek within the buffer.
591      But to be able to switch to reading, we would need to set
592      egptr to ptr.  That can't be done in the current design,
593      which assumes file_ptr() is eGptr.  Anyway, since we probably
594      end up flushing when we close(), it doesn't make much difference.)
595      FIXME: simulate mem-mapped files. */
596
597   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
598       || _IO_in_put_mode (fp))
599     if (INTUSE(_IO_switch_to_wget_mode) (fp))
600       return WEOF;
601
602   if (fp->_wide_data->_IO_buf_base == NULL)
603     {
604       /* It could be that we already have a pushback buffer.  */
605       if (fp->_wide_data->_IO_read_base != NULL)
606         {
607           free (fp->_wide_data->_IO_read_base);
608           fp->_flags &= ~_IO_IN_BACKUP;
609         }
610       INTUSE(_IO_doallocbuf) (fp);
611       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
612       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
613       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
614                  fp->_wide_data->_IO_buf_base);
615       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
616                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
617     }
618
619   switch (dir)
620     {
621       struct _IO_codecvt *cv;
622       int clen;
623
624     case _IO_seek_cur:
625       /* Adjust for read-ahead (bytes is buffer).  To do this we must
626          find out which position in the external buffer corresponds to
627          the current position in the internal buffer.  */
628       cv = fp->_codecvt;
629       clen = (*cv->__codecvt_do_encoding) (cv);
630
631       if (clen > 0)
632         {
633           offset -= (fp->_wide_data->_IO_read_end
634                      - fp->_wide_data->_IO_read_ptr) * clen;
635           /* Adjust by readahead in external buffer.  */
636           offset -= fp->_IO_read_end - fp->_IO_read_ptr;
637         }
638       else
639         {
640           int nread;
641
642           delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
643           fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
644           nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
645                                               fp->_IO_read_base,
646                                               fp->_IO_read_end, delta);
647           fp->_IO_read_ptr = fp->_IO_read_base + nread;
648           fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
649           offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
650         }
651
652       if (fp->_offset == _IO_pos_BAD)
653         goto dumb;
654       /* Make offset absolute, assuming current pointer is file_ptr(). */
655       offset += fp->_offset;
656
657       dir = _IO_seek_set;
658       break;
659     case _IO_seek_set:
660       break;
661     case _IO_seek_end:
662       {
663         struct _G_stat64 st;
664         if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
665           {
666             offset += st.st_size;
667             dir = _IO_seek_set;
668           }
669         else
670           goto dumb;
671       }
672     }
673   /* At this point, dir==_IO_seek_set. */
674
675   /* If we are only interested in the current position we've found it now.  */
676   if (mode == 0)
677     return offset;
678
679   /* If destination is within current buffer, optimize: */
680   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
681       && !_IO_in_backup (fp))
682     {
683       _IO_off64_t start_offset = (fp->_offset
684                                   - (fp->_IO_read_end - fp->_IO_buf_base));
685       if (offset >= start_offset && offset < fp->_offset)
686         {
687           _IO_setg (fp, fp->_IO_buf_base,
688                     fp->_IO_buf_base + (offset - start_offset),
689                     fp->_IO_read_end);
690           _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
691           _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
692                      fp->_wide_data->_IO_buf_base,
693                      fp->_wide_data->_IO_buf_base);
694           _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
695                      fp->_wide_data->_IO_buf_base);
696           _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
697           goto resync;
698         }
699     }
700
701   if (fp->_flags & _IO_NO_READS)
702     goto dumb;
703
704   /* Try to seek to a block boundary, to improve kernel page management. */
705   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
706   delta = offset - new_offset;
707   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
708     {
709       new_offset = offset;
710       delta = 0;
711     }
712   result = _IO_SYSSEEK (fp, new_offset, 0);
713   if (result < 0)
714     return EOF;
715   if (delta == 0)
716     count = 0;
717   else
718     {
719       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
720                            (must_be_exact
721                             ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
722       if (count < delta)
723         {
724           /* We weren't allowed to read, but try to seek the remainder. */
725           offset = count == EOF ? delta : delta-count;
726           dir = _IO_seek_cur;
727           goto dumb;
728         }
729     }
730   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
731             fp->_IO_buf_base + count);
732   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
733   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
734              fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
735   _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
736   fp->_offset = result + count;
737   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
738   return offset;
739  dumb:
740
741   INTUSE(_IO_unsave_markers) (fp);
742   result = _IO_SYSSEEK (fp, offset, dir);
743   if (result != EOF)
744     {
745       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
746       fp->_offset = result;
747       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
748       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
749       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
750                  fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
751       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
752                  fp->_wide_data->_IO_buf_base);
753     }
754   return result;
755
756 resync:
757   /* We need to do it since it is possible that the file offset in
758      the kernel may be changed behind our back. It may happen when
759      we fopen a file and then do a fork. One process may access the
760      file and the kernel file offset will be changed. */
761   if (fp->_offset >= 0)
762     _IO_SYSSEEK (fp, fp->_offset, 0);
763
764   return offset;
765 }
766 INTDEF(_IO_wfile_seekoff)
767
768
769 _IO_size_t
770 _IO_wfile_xsputn (f, data, n)
771      _IO_FILE *f;
772      const void *data;
773      _IO_size_t n;
774 {
775   register const wchar_t *s = (const wchar_t *) data;
776   _IO_size_t to_do = n;
777   int must_flush = 0;
778   _IO_size_t count;
779
780   if (n <= 0)
781     return 0;
782   /* This is an optimized implementation.
783      If the amount to be written straddles a block boundary
784      (or the filebuf is unbuffered), use sys_write directly. */
785
786   /* First figure out how much space is available in the buffer. */
787   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
788   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
789     {
790       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
791       if (count >= n)
792         {
793           register const wchar_t *p;
794           for (p = s + n; p > s; )
795             {
796               if (*--p == L'\n')
797                 {
798                   count = p - s + 1;
799                   must_flush = 1;
800                   break;
801                 }
802             }
803         }
804     }
805   /* Then fill the buffer. */
806   if (count > 0)
807     {
808       if (count > to_do)
809         count = to_do;
810       if (count > 20)
811         {
812 #ifdef _LIBC
813           f->_wide_data->_IO_write_ptr =
814             __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
815 #else
816           wmemcpy (f->_wide_data->_IO_write_ptr, s, count);
817           f->_wide_data->_IO_write_ptr += count;
818 #endif
819           s += count;
820         }
821       else
822         {
823           register wchar_t *p = f->_wide_data->_IO_write_ptr;
824           register int i = (int) count;
825           while (--i >= 0)
826             *p++ = *s++;
827           f->_wide_data->_IO_write_ptr = p;
828         }
829       to_do -= count;
830     }
831   if (to_do > 0)
832     to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);
833   if (must_flush
834       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
835     INTUSE(_IO_wdo_write) (f, f->_wide_data->_IO_write_base,
836                            f->_wide_data->_IO_write_ptr
837                            - f->_wide_data->_IO_write_base);
838
839   return n - to_do;
840 }
841 INTDEF(_IO_wfile_xsputn)
842
843
844 const struct _IO_jump_t _IO_wfile_jumps =
845 {
846   JUMP_INIT_DUMMY,
847   JUMP_INIT(finish, _IO_new_file_finish),
848   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
849   JUMP_INIT(underflow, (_IO_underflow_t) INTUSE(_IO_wfile_underflow)),
850   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
851   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
852   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
853   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
854   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
855   JUMP_INIT(seekpos, _IO_default_seekpos),
856   JUMP_INIT(setbuf, _IO_new_file_setbuf),
857   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
858   JUMP_INIT(doallocate, _IO_wfile_doallocate),
859   JUMP_INIT(read, INTUSE(_IO_file_read)),
860   JUMP_INIT(write, _IO_new_file_write),
861   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
862   JUMP_INIT(close, INTUSE(_IO_file_close)),
863   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
864   JUMP_INIT(showmanyc, _IO_default_showmanyc),
865   JUMP_INIT(imbue, _IO_default_imbue)
866 };
867 libc_hidden_data_def (_IO_wfile_jumps)
868
869
870 const struct _IO_jump_t _IO_wfile_jumps_mmap =
871 {
872   JUMP_INIT_DUMMY,
873   JUMP_INIT(finish, _IO_new_file_finish),
874   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
875   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
876   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
877   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
878   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
879   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
880   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
881   JUMP_INIT(seekpos, _IO_default_seekpos),
882   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
883   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
884   JUMP_INIT(doallocate, _IO_wfile_doallocate),
885   JUMP_INIT(read, INTUSE(_IO_file_read)),
886   JUMP_INIT(write, _IO_new_file_write),
887   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
888   JUMP_INIT(close, _IO_file_close_mmap),
889   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
890   JUMP_INIT(showmanyc, _IO_default_showmanyc),
891   JUMP_INIT(imbue, _IO_default_imbue)
892 };
893
894 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
895 {
896   JUMP_INIT_DUMMY,
897   JUMP_INIT(finish, _IO_new_file_finish),
898   JUMP_INIT(overflow, (_IO_overflow_t) INTUSE(_IO_wfile_overflow)),
899   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
900   JUMP_INIT(uflow, (_IO_underflow_t) INTUSE(_IO_wdefault_uflow)),
901   JUMP_INIT(pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
902   JUMP_INIT(xsputn, INTUSE(_IO_wfile_xsputn)),
903   JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
904   JUMP_INIT(seekoff, INTUSE(_IO_wfile_seekoff)),
905   JUMP_INIT(seekpos, _IO_default_seekpos),
906   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
907   JUMP_INIT(sync, (_IO_sync_t) INTUSE(_IO_wfile_sync)),
908   JUMP_INIT(doallocate, _IO_wfile_doallocate),
909   JUMP_INIT(read, INTUSE(_IO_file_read)),
910   JUMP_INIT(write, _IO_new_file_write),
911   JUMP_INIT(seek, INTUSE(_IO_file_seek)),
912   JUMP_INIT(close, INTUSE(_IO_file_close)),
913   JUMP_INIT(stat, INTUSE(_IO_file_stat)),
914   JUMP_INIT(showmanyc, _IO_default_showmanyc),
915   JUMP_INIT(imbue, _IO_default_imbue)
916 };