1 /* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.
17 
18    As a special exception, if you link the code in this file with
19    files compiled with a GNU compiler to produce an executable,
20    that does not cause the resulting executable to be covered by
21    the GNU Lesser General Public License.  This exception does not
22    however invalidate any other reasons why the executable file
23    might be covered by the GNU Lesser General Public License.
24    This exception applies to code released by its copyright holders
25    in files containing the exception.  */
26 
27 #include <assert.h>
28 #include <libioP.h>
29 #include <wchar.h>
30 #include <gconv.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 /* Convert TO_DO wide character from DATA to FP.
35    Then mark FP as having empty buffers. */
36 int
_IO_wdo_write(FILE * fp,const wchar_t * data,size_t to_do)37 _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)
38 {
39   struct _IO_codecvt *cc = fp->_codecvt;
40 
41   if (to_do > 0)
42     {
43       if (fp->_IO_write_end == fp->_IO_write_ptr
44 	  && fp->_IO_write_end != fp->_IO_write_base)
45 	{
46 	  if (_IO_new_do_write (fp, fp->_IO_write_base,
47 				fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
48 	    return WEOF;
49 	}
50 
51       do
52 	{
53 	  enum __codecvt_result result;
54 	  const wchar_t *new_data;
55 	  char mb_buf[MB_LEN_MAX];
56 	  char *write_base, *write_ptr, *buf_end;
57 
58 	  if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf))
59 	    {
60 	      /* Make sure we have room for at least one multibyte
61 		 character.  */
62 	      write_ptr = write_base = mb_buf;
63 	      buf_end = mb_buf + sizeof (mb_buf);
64 	    }
65 	  else
66 	    {
67 	      write_ptr = fp->_IO_write_ptr;
68 	      write_base = fp->_IO_write_base;
69 	      buf_end = fp->_IO_buf_end;
70 	    }
71 
72 	  /* Now convert from the internal format into the external buffer.  */
73 	  result = __libio_codecvt_out (cc, &fp->_wide_data->_IO_state,
74 					data, data + to_do, &new_data,
75 					write_ptr,
76 					buf_end,
77 					&write_ptr);
78 
79 	  /* Write out what we produced so far.  */
80 	  if (_IO_new_do_write (fp, write_base, write_ptr - write_base) == EOF)
81 	    /* Something went wrong.  */
82 	    return WEOF;
83 
84 	  to_do -= new_data - data;
85 
86 	  /* Next see whether we had problems during the conversion.  If yes,
87 	     we cannot go on.  */
88 	  if (result != __codecvt_ok
89 	      && (result != __codecvt_partial || new_data - data == 0))
90 	    break;
91 
92 	  data = new_data;
93 	}
94       while (to_do > 0);
95     }
96 
97   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base,
98 	     fp->_wide_data->_IO_buf_base);
99   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr
100     = fp->_wide_data->_IO_buf_base;
101   fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
102 				   ? fp->_wide_data->_IO_buf_base
103 				   : fp->_wide_data->_IO_buf_end);
104 
105   return to_do == 0 ? 0 : WEOF;
106 }
libc_hidden_def(_IO_wdo_write)107 libc_hidden_def (_IO_wdo_write)
108 
109 
110 wint_t
111 _IO_wfile_underflow (FILE *fp)
112 {
113   struct _IO_codecvt *cd;
114   enum __codecvt_result status;
115   ssize_t count;
116 
117   /* C99 requires EOF to be "sticky".  */
118   if (fp->_flags & _IO_EOF_SEEN)
119     return WEOF;
120 
121   if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
122     {
123       fp->_flags |= _IO_ERR_SEEN;
124       __set_errno (EBADF);
125       return WEOF;
126     }
127   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
128     return *fp->_wide_data->_IO_read_ptr;
129 
130   cd = fp->_codecvt;
131 
132   /* Maybe there is something left in the external buffer.  */
133   if (fp->_IO_read_ptr < fp->_IO_read_end)
134     {
135       /* There is more in the external.  Convert it.  */
136       const char *read_stop = (const char *) fp->_IO_read_ptr;
137 
138       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
139       fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
140 	fp->_wide_data->_IO_buf_base;
141       status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
142 				   fp->_IO_read_ptr, fp->_IO_read_end,
143 				   &read_stop,
144 				   fp->_wide_data->_IO_read_ptr,
145 				   fp->_wide_data->_IO_buf_end,
146 				   &fp->_wide_data->_IO_read_end);
147 
148       fp->_IO_read_base = fp->_IO_read_ptr;
149       fp->_IO_read_ptr = (char *) read_stop;
150 
151       /* If we managed to generate some text return the next character.  */
152       if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
153 	return *fp->_wide_data->_IO_read_ptr;
154 
155       if (status == __codecvt_error)
156 	{
157 	  __set_errno (EILSEQ);
158 	  fp->_flags |= _IO_ERR_SEEN;
159 	  return WEOF;
160 	}
161 
162       /* Move the remaining content of the read buffer to the beginning.  */
163       memmove (fp->_IO_buf_base, fp->_IO_read_ptr,
164 	       fp->_IO_read_end - fp->_IO_read_ptr);
165       fp->_IO_read_end = (fp->_IO_buf_base
166 			  + (fp->_IO_read_end - fp->_IO_read_ptr));
167       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
168     }
169   else
170     fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
171       fp->_IO_buf_base;
172 
173   if (fp->_IO_buf_base == NULL)
174     {
175       /* Maybe we already have a push back pointer.  */
176       if (fp->_IO_save_base != NULL)
177 	{
178 	  free (fp->_IO_save_base);
179 	  fp->_flags &= ~_IO_IN_BACKUP;
180 	}
181       _IO_doallocbuf (fp);
182 
183       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_read_end =
184 	fp->_IO_buf_base;
185     }
186 
187   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end =
188     fp->_IO_buf_base;
189 
190   if (fp->_wide_data->_IO_buf_base == NULL)
191     {
192       /* Maybe we already have a push back pointer.  */
193       if (fp->_wide_data->_IO_save_base != NULL)
194 	{
195 	  free (fp->_wide_data->_IO_save_base);
196 	  fp->_flags &= ~_IO_IN_BACKUP;
197 	}
198       _IO_wdoallocbuf (fp);
199     }
200 
201   /* FIXME This can/should be moved to genops ?? */
202   if (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
203     {
204       /* We used to flush all line-buffered stream.  This really isn't
205 	 required by any standard.  My recollection is that
206 	 traditional Unix systems did this for stdout.  stderr better
207 	 not be line buffered.  So we do just that here
208 	 explicitly.  --drepper */
209       _IO_acquire_lock (stdout);
210 
211       if ((stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
212 	  == (_IO_LINKED | _IO_LINE_BUF))
213 	_IO_OVERFLOW (stdout, EOF);
214 
215       _IO_release_lock (stdout);
216     }
217 
218   _IO_switch_to_get_mode (fp);
219 
220   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
221     fp->_wide_data->_IO_buf_base;
222   fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_buf_base;
223   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
224     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
225 
226   const char *read_ptr_copy;
227   char accbuf[MB_LEN_MAX];
228   size_t naccbuf = 0;
229  again:
230   count = _IO_SYSREAD (fp, fp->_IO_read_end,
231 		       fp->_IO_buf_end - fp->_IO_read_end);
232   if (count <= 0)
233     {
234       if (count == 0 && naccbuf == 0)
235 	{
236 	  fp->_flags |= _IO_EOF_SEEN;
237 	  fp->_offset = _IO_pos_BAD;
238 	}
239       else
240 	fp->_flags |= _IO_ERR_SEEN, count = 0;
241     }
242   fp->_IO_read_end += count;
243   if (count == 0)
244     {
245       if (naccbuf != 0)
246 	/* There are some bytes in the external buffer but they don't
247 	   convert to anything.  */
248 	__set_errno (EILSEQ);
249       return WEOF;
250     }
251   if (fp->_offset != _IO_pos_BAD)
252     _IO_pos_adjust (fp->_offset, count);
253 
254   /* Now convert the read input.  */
255   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
256   fp->_IO_read_base = fp->_IO_read_ptr;
257   const char *from = fp->_IO_read_ptr;
258   const char *to = fp->_IO_read_end;
259   size_t to_copy = count;
260   if (__glibc_unlikely (naccbuf != 0))
261     {
262       to_copy = MIN (sizeof (accbuf) - naccbuf, count);
263       to = __mempcpy (&accbuf[naccbuf], from, to_copy);
264       naccbuf += to_copy;
265       from = accbuf;
266     }
267   status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
268 			       from, to, &read_ptr_copy,
269 			       fp->_wide_data->_IO_read_end,
270 			       fp->_wide_data->_IO_buf_end,
271 			       &fp->_wide_data->_IO_read_end);
272 
273   if (__glibc_unlikely (naccbuf != 0))
274     fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
275   else
276     fp->_IO_read_ptr = (char *) read_ptr_copy;
277   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
278     {
279       if (status == __codecvt_error)
280 	{
281 	out_eilseq:
282 	  __set_errno (EILSEQ);
283 	  fp->_flags |= _IO_ERR_SEEN;
284 	  return WEOF;
285 	}
286 
287       /* The read bytes make no complete character.  Try reading again.  */
288       assert (status == __codecvt_partial);
289 
290       if (naccbuf == 0)
291 	{
292 	  if (fp->_IO_read_base < fp->_IO_read_ptr)
293 	    {
294 	      /* Partially used the buffer for some input data that
295 		 produces no output.  */
296 	      size_t avail = fp->_IO_read_end - fp->_IO_read_ptr;
297 	      memmove (fp->_IO_read_base, fp->_IO_read_ptr, avail);
298 	      fp->_IO_read_ptr = fp->_IO_read_base;
299 	      fp->_IO_read_end -= avail;
300 	      goto again;
301 	    }
302 	  naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
303 	  if (naccbuf >= sizeof (accbuf))
304 	    goto out_eilseq;
305 
306 	  memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
307 	}
308       else
309 	{
310 	  size_t used = read_ptr_copy - accbuf;
311 	  if (used > 0)
312 	    {
313 	      memmove (accbuf, read_ptr_copy, naccbuf - used);
314 	      naccbuf -= used;
315 	    }
316 
317 	  if (naccbuf == sizeof (accbuf))
318 	    goto out_eilseq;
319 	}
320 
321       fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
322 
323       goto again;
324     }
325 
326   return *fp->_wide_data->_IO_read_ptr;
327 }
libc_hidden_def(_IO_wfile_underflow)328 libc_hidden_def (_IO_wfile_underflow)
329 
330 
331 static wint_t
332 _IO_wfile_underflow_mmap (FILE *fp)
333 {
334   struct _IO_codecvt *cd;
335   const char *read_stop;
336 
337   if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
338     {
339       fp->_flags |= _IO_ERR_SEEN;
340       __set_errno (EBADF);
341       return WEOF;
342     }
343   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
344     return *fp->_wide_data->_IO_read_ptr;
345 
346   cd = fp->_codecvt;
347 
348   /* Maybe there is something left in the external buffer.  */
349   if (fp->_IO_read_ptr >= fp->_IO_read_end
350       /* No.  But maybe the read buffer is not fully set up.  */
351       && _IO_file_underflow_mmap (fp) == EOF)
352     /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
353        flags as appropriate.  */
354     return WEOF;
355 
356   /* There is more in the external.  Convert it.  */
357   read_stop = (const char *) fp->_IO_read_ptr;
358 
359   if (fp->_wide_data->_IO_buf_base == NULL)
360     {
361       /* Maybe we already have a push back pointer.  */
362       if (fp->_wide_data->_IO_save_base != NULL)
363 	{
364 	  free (fp->_wide_data->_IO_save_base);
365 	  fp->_flags &= ~_IO_IN_BACKUP;
366 	}
367       _IO_wdoallocbuf (fp);
368     }
369 
370   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
371   fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
372     fp->_wide_data->_IO_buf_base;
373   __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
374 		      fp->_IO_read_ptr, fp->_IO_read_end,
375 		      &read_stop,
376 		      fp->_wide_data->_IO_read_ptr,
377 		      fp->_wide_data->_IO_buf_end,
378 		      &fp->_wide_data->_IO_read_end);
379 
380   fp->_IO_read_ptr = (char *) read_stop;
381 
382   /* If we managed to generate some text return the next character.  */
383   if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
384     return *fp->_wide_data->_IO_read_ptr;
385 
386   /* There is some garbage at the end of the file.  */
387   __set_errno (EILSEQ);
388   fp->_flags |= _IO_ERR_SEEN;
389   return WEOF;
390 }
391 
392 static wint_t
_IO_wfile_underflow_maybe_mmap(FILE * fp)393 _IO_wfile_underflow_maybe_mmap (FILE *fp)
394 {
395   /* This is the first read attempt.  Doing the underflow will choose mmap
396      or vanilla operations and then punt to the chosen underflow routine.
397      Then we can punt to ours.  */
398   if (_IO_file_underflow_maybe_mmap (fp) == EOF)
399     return WEOF;
400 
401   return _IO_WUNDERFLOW (fp);
402 }
403 
404 
405 wint_t
_IO_wfile_overflow(FILE * f,wint_t wch)406 _IO_wfile_overflow (FILE *f, wint_t wch)
407 {
408   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
409     {
410       f->_flags |= _IO_ERR_SEEN;
411       __set_errno (EBADF);
412       return WEOF;
413     }
414   /* If currently reading or no buffer allocated. */
415   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0
416       || f->_wide_data->_IO_write_base == NULL)
417     {
418       /* Allocate a buffer if needed. */
419       if (f->_wide_data->_IO_write_base == 0)
420 	{
421 	  _IO_wdoallocbuf (f);
422 	  _IO_free_wbackup_area (f);
423 	  _IO_wsetg (f, f->_wide_data->_IO_buf_base,
424 		     f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
425 
426 	  if (f->_IO_write_base == NULL)
427 	    {
428 	      _IO_doallocbuf (f);
429 	      _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
430 	    }
431 	}
432       else
433 	{
434 	  /* Otherwise must be currently reading.  If _IO_read_ptr
435 	     (and hence also _IO_read_end) is at the buffer end,
436 	     logically slide the buffer forwards one block (by setting
437 	     the read pointers to all point at the beginning of the
438 	     block).  This makes room for subsequent output.
439 	     Otherwise, set the read pointers to _IO_read_end (leaving
440 	     that alone, so it can continue to correspond to the
441 	     external position). */
442 	  if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
443 	    {
444 	      f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
445 	      f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
446 		f->_wide_data->_IO_buf_base;
447 	    }
448 	}
449       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
450       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
451       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
452       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
453 	f->_wide_data->_IO_read_end;
454 
455       f->_IO_write_ptr = f->_IO_read_ptr;
456       f->_IO_write_base = f->_IO_write_ptr;
457       f->_IO_write_end = f->_IO_buf_end;
458       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
459 
460       f->_flags |= _IO_CURRENTLY_PUTTING;
461       if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
462 	f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
463     }
464   if (wch == WEOF)
465     return _IO_do_flush (f);
466   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
467     /* Buffer is really full */
468     if (_IO_do_flush (f) == EOF)
469       return WEOF;
470   *f->_wide_data->_IO_write_ptr++ = wch;
471   if ((f->_flags & _IO_UNBUFFERED)
472       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
473     if (_IO_do_flush (f) == EOF)
474       return WEOF;
475   return wch;
476 }
libc_hidden_def(_IO_wfile_overflow)477 libc_hidden_def (_IO_wfile_overflow)
478 
479 wint_t
480 _IO_wfile_sync (FILE *fp)
481 {
482   ssize_t delta;
483   wint_t retval = 0;
484 
485   /*    char* ptr = cur_ptr(); */
486   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
487     if (_IO_do_flush (fp))
488       return WEOF;
489   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
490   if (delta != 0)
491     {
492       /* We have to find out how many bytes we have to go back in the
493 	 external buffer.  */
494       struct _IO_codecvt *cv = fp->_codecvt;
495       off64_t new_pos;
496 
497       int clen = __libio_codecvt_encoding (cv);
498 
499       if (clen > 0)
500 	/* It is easy, a fixed number of input bytes are used for each
501 	   wide character.  */
502 	delta *= clen;
503       else
504 	{
505 	  /* We have to find out the hard way how much to back off.
506 	     To do this we determine how much input we needed to
507 	     generate the wide characters up to the current reading
508 	     position.  */
509 	  int nread;
510 	  size_t wnread = (fp->_wide_data->_IO_read_ptr
511 			   - fp->_wide_data->_IO_read_base);
512 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
513 	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,
514 					  fp->_IO_read_base,
515 					  fp->_IO_read_end, wnread);
516 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
517 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
518 	}
519 
520       new_pos = _IO_SYSSEEK (fp, delta, 1);
521       if (new_pos != (off64_t) EOF)
522 	{
523 	  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
524 	  fp->_IO_read_end = fp->_IO_read_ptr;
525 	}
526       else if (errno == ESPIPE)
527 	; /* Ignore error from unseekable devices. */
528       else
529 	retval = WEOF;
530     }
531   if (retval != WEOF)
532     fp->_offset = _IO_pos_BAD;
533   /* FIXME: Cleanup - can this be shared? */
534   /*    setg(base(), ptr, ptr); */
535   return retval;
536 }
libc_hidden_def(_IO_wfile_sync)537 libc_hidden_def (_IO_wfile_sync)
538 
539 /* Adjust the internal buffer pointers to reflect the state in the external
540    buffer.  The content between fp->_IO_read_base and fp->_IO_read_ptr is
541    assumed to be converted and available in the range
542    fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
543 
544    Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set.  */
545 static int
546 adjust_wide_data (FILE *fp, bool do_convert)
547 {
548   struct _IO_codecvt *cv = fp->_codecvt;
549 
550   int clen = __libio_codecvt_encoding (cv);
551 
552   /* Take the easy way out for constant length encodings if we don't need to
553      convert.  */
554   if (!do_convert && clen > 0)
555     {
556       fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
557 				       / clen);
558       goto done;
559     }
560 
561   enum __codecvt_result status;
562   const char *read_stop = (const char *) fp->_IO_read_base;
563   do
564     {
565 
566       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
567       status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,
568 				   fp->_IO_read_base, fp->_IO_read_ptr,
569 				   &read_stop,
570 				   fp->_wide_data->_IO_read_base,
571 				   fp->_wide_data->_IO_buf_end,
572 				   &fp->_wide_data->_IO_read_end);
573 
574       /* Should we return EILSEQ?  */
575       if (__glibc_unlikely (status == __codecvt_error))
576 	{
577 	  fp->_flags |= _IO_ERR_SEEN;
578 	  return -1;
579 	}
580     }
581   while (__builtin_expect (status == __codecvt_partial, 0));
582 
583 done:
584   /* Now seek to _IO_read_end to behave as if we have read it all in.  */
585   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
586 
587   return 0;
588 }
589 
590 /* ftell{,o} implementation for wide mode.  Don't modify any state of the file
591    pointer while we try to get the current state of the stream except in one
592    case, which is when we have unflushed writes in append mode.  */
593 static off64_t
do_ftell_wide(FILE * fp)594 do_ftell_wide (FILE *fp)
595 {
596   off64_t result, offset = 0;
597 
598   /* No point looking for offsets in the buffer if it hasn't even been
599      allocated.  */
600   if (fp->_wide_data->_IO_buf_base != NULL)
601     {
602       const wchar_t *wide_read_base;
603       const wchar_t *wide_read_ptr;
604       const wchar_t *wide_read_end;
605       bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
606 			       > fp->_wide_data->_IO_write_base);
607 
608       bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
609 
610       /* When we have unflushed writes in append mode, seek to the end of the
611 	 file and record that offset.  This is the only time we change the file
612 	 stream state and it is safe since the file handle is active.  */
613       if (unflushed_writes && append_mode)
614 	{
615 	  result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
616 	  if (result == _IO_pos_BAD)
617 	    return EOF;
618 	  else
619 	    fp->_offset = result;
620 	}
621 
622       /* XXX For wide stream with backup store it is not very
623 	 reasonable to determine the offset.  The pushed-back
624 	 character might require a state change and we need not be
625 	 able to compute the initial state by reverse transformation
626 	 since there is no guarantee of symmetry.  So we don't even
627 	 try and return an error.  */
628       if (_IO_in_backup (fp))
629 	{
630 	  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
631 	    {
632 	      __set_errno (EINVAL);
633 	      return -1;
634 	    }
635 
636 	  /* Nothing in the backup store, so note the backed up pointers
637 	     without changing the state.  */
638 	  wide_read_base = fp->_wide_data->_IO_save_base;
639 	  wide_read_ptr = wide_read_base;
640 	  wide_read_end = fp->_wide_data->_IO_save_end;
641 	}
642       else
643 	{
644 	  wide_read_base = fp->_wide_data->_IO_read_base;
645 	  wide_read_ptr = fp->_wide_data->_IO_read_ptr;
646 	  wide_read_end = fp->_wide_data->_IO_read_end;
647 	}
648 
649       struct _IO_codecvt *cv = fp->_codecvt;
650       int clen = __libio_codecvt_encoding (cv);
651 
652       if (!unflushed_writes)
653 	{
654 	  if (clen > 0)
655 	    {
656 	      offset -= (wide_read_end - wide_read_ptr) * clen;
657 	      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
658 	    }
659 	  else
660 	    {
661 	      int nread;
662 
663 	      size_t delta = wide_read_ptr - wide_read_base;
664 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
665 	      nread = __libio_codecvt_length (cv, &state,
666 					      fp->_IO_read_base,
667 					      fp->_IO_read_end, delta);
668 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
669 	    }
670 	}
671       else
672 	{
673 	  if (clen > 0)
674 	    offset += (fp->_wide_data->_IO_write_ptr
675 		       - fp->_wide_data->_IO_write_base) * clen;
676 	  else
677 	    {
678 	      size_t delta = (fp->_wide_data->_IO_write_ptr
679 			      - fp->_wide_data->_IO_write_base);
680 
681 	      /* Allocate enough space for the conversion.  */
682 	      size_t outsize = delta * sizeof (wchar_t);
683 	      char *out = malloc (outsize);
684 	      char *outstop = out;
685 	      const wchar_t *in = fp->_wide_data->_IO_write_base;
686 
687 	      enum __codecvt_result status;
688 
689 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
690 	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,
691 					    out, out + outsize, &outstop);
692 
693 	      /* We don't check for __codecvt_partial because it can be
694 		 returned on one of two conditions: either the output
695 		 buffer is full or the input sequence is incomplete.  We
696 		 take care to allocate enough buffer and our input
697 		 sequences must be complete since they are accepted as
698 		 wchar_t; if not, then that is an error.  */
699 	      if (__glibc_unlikely (status != __codecvt_ok))
700 		{
701 		  free (out);
702 		  return WEOF;
703 		}
704 
705 	      offset += outstop - out;
706 	      free (out);
707 	    }
708 
709 	  /* We don't trust _IO_read_end to represent the current file offset
710 	     when writing in append mode because the value would have to be
711 	     shifted to the end of the file during a flush.  Use the write base
712 	     instead, along with the new offset we got above when we did a seek
713 	     to the end of the file.  */
714 	  if (append_mode)
715 	    offset += fp->_IO_write_ptr - fp->_IO_write_base;
716 	  /* For all other modes, _IO_read_end represents the file offset.  */
717 	  else
718 	    offset += fp->_IO_write_ptr - fp->_IO_read_end;
719 	}
720     }
721 
722   if (fp->_offset != _IO_pos_BAD)
723     result = fp->_offset;
724   else
725     result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
726 
727   if (result == EOF)
728     return result;
729 
730   result += offset;
731 
732   if (result < 0)
733     {
734       __set_errno (EINVAL);
735       return EOF;
736     }
737 
738   return result;
739 }
740 
741 off64_t
_IO_wfile_seekoff(FILE * fp,off64_t offset,int dir,int mode)742 _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
743 {
744   off64_t result;
745   off64_t delta, new_offset;
746   long int count;
747 
748   /* Short-circuit into a separate function.  We don't want to mix any
749      functionality and we don't want to touch anything inside the FILE
750      object. */
751   if (mode == 0)
752     return do_ftell_wide (fp);
753 
754   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
755      offset of the underlying file must be exact.  */
756   int must_be_exact = ((fp->_wide_data->_IO_read_base
757 			== fp->_wide_data->_IO_read_end)
758 		       && (fp->_wide_data->_IO_write_base
759 			   == fp->_wide_data->_IO_write_ptr));
760 
761   bool was_writing = ((fp->_wide_data->_IO_write_ptr
762 		       > fp->_wide_data->_IO_write_base)
763 		      || _IO_in_put_mode (fp));
764 
765   /* Flush unwritten characters.
766      (This may do an unneeded write if we seek within the buffer.
767      But to be able to switch to reading, we would need to set
768      egptr to pptr.  That can't be done in the current design,
769      which assumes file_ptr() is eGptr.  Anyway, since we probably
770      end up flushing when we close(), it doesn't make much difference.)
771      FIXME: simulate mem-mapped files. */
772   if (was_writing && _IO_switch_to_wget_mode (fp))
773     return WEOF;
774 
775   if (fp->_wide_data->_IO_buf_base == NULL)
776     {
777       /* It could be that we already have a pushback buffer.  */
778       if (fp->_wide_data->_IO_read_base != NULL)
779 	{
780 	  free (fp->_wide_data->_IO_read_base);
781 	  fp->_flags &= ~_IO_IN_BACKUP;
782 	}
783       _IO_doallocbuf (fp);
784       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
785       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
786       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
787 		 fp->_wide_data->_IO_buf_base);
788       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
789 		 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
790     }
791 
792   switch (dir)
793     {
794       struct _IO_codecvt *cv;
795       int clen;
796 
797     case _IO_seek_cur:
798       /* Adjust for read-ahead (bytes is buffer).  To do this we must
799 	 find out which position in the external buffer corresponds to
800 	 the current position in the internal buffer.  */
801       cv = fp->_codecvt;
802       clen = __libio_codecvt_encoding (cv);
803 
804       if (mode != 0 || !was_writing)
805 	{
806 	  if (clen > 0)
807 	    {
808 	      offset -= (fp->_wide_data->_IO_read_end
809 			 - fp->_wide_data->_IO_read_ptr) * clen;
810 	      /* Adjust by readahead in external buffer.  */
811 	      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
812 	    }
813 	  else
814 	    {
815 	      int nread;
816 
817 	      delta = (fp->_wide_data->_IO_read_ptr
818 		       - fp->_wide_data->_IO_read_base);
819 	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
820 	      nread = __libio_codecvt_length (cv,
821 					      &fp->_wide_data->_IO_state,
822 					      fp->_IO_read_base,
823 					      fp->_IO_read_end, delta);
824 	      fp->_IO_read_ptr = fp->_IO_read_base + nread;
825 	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
826 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
827 	    }
828 	}
829 
830       if (fp->_offset == _IO_pos_BAD)
831 	goto dumb;
832 
833       /* Make offset absolute, assuming current pointer is file_ptr(). */
834       offset += fp->_offset;
835 
836       dir = _IO_seek_set;
837       break;
838     case _IO_seek_set:
839       break;
840     case _IO_seek_end:
841       {
842 	struct __stat64_t64 st;
843 	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
844 	  {
845 	    offset += st.st_size;
846 	    dir = _IO_seek_set;
847 	  }
848 	else
849 	  goto dumb;
850       }
851     }
852 
853   _IO_free_wbackup_area (fp);
854 
855   /* At this point, dir==_IO_seek_set. */
856 
857   /* If destination is within current buffer, optimize: */
858   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
859       && !_IO_in_backup (fp))
860     {
861       off64_t start_offset = (fp->_offset
862                               - (fp->_IO_read_end - fp->_IO_buf_base));
863       if (offset >= start_offset && offset < fp->_offset)
864 	{
865 	  _IO_setg (fp, fp->_IO_buf_base,
866 		    fp->_IO_buf_base + (offset - start_offset),
867 		    fp->_IO_read_end);
868 	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
869 	  _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
870 		     fp->_wide_data->_IO_buf_base,
871 		     fp->_wide_data->_IO_buf_base);
872 	  _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
873 		     fp->_wide_data->_IO_buf_base);
874 
875 	  if (adjust_wide_data (fp, false))
876 	    goto dumb;
877 
878 	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
879 	  goto resync;
880 	}
881     }
882 
883   if (fp->_flags & _IO_NO_READS)
884     goto dumb;
885 
886   /* Try to seek to a block boundary, to improve kernel page management. */
887   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
888   delta = offset - new_offset;
889   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
890     {
891       new_offset = offset;
892       delta = 0;
893     }
894   result = _IO_SYSSEEK (fp, new_offset, 0);
895   if (result < 0)
896     return EOF;
897   if (delta == 0)
898     count = 0;
899   else
900     {
901       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
902 			   (must_be_exact
903 			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
904       if (count < delta)
905 	{
906 	  /* We weren't allowed to read, but try to seek the remainder. */
907 	  offset = count == EOF ? delta : delta-count;
908 	  dir = _IO_seek_cur;
909 	  goto dumb;
910 	}
911     }
912   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
913 	    fp->_IO_buf_base + count);
914   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
915   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
916 	     fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
917   _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
918 
919   if (adjust_wide_data (fp, true))
920     goto dumb;
921 
922   fp->_offset = result + count;
923   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
924   return offset;
925  dumb:
926 
927   _IO_unsave_markers (fp);
928   result = _IO_SYSSEEK (fp, offset, dir);
929   if (result != EOF)
930     {
931       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
932       fp->_offset = result;
933       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
934       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
935       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
936 		 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
937       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
938 		 fp->_wide_data->_IO_buf_base);
939     }
940   return result;
941 
942 resync:
943   /* We need to do it since it is possible that the file offset in
944      the kernel may be changed behind our back. It may happen when
945      we fopen a file and then do a fork. One process may access the
946      file and the kernel file offset will be changed. */
947   if (fp->_offset >= 0)
948     _IO_SYSSEEK (fp, fp->_offset, 0);
949 
950   return offset;
951 }
libc_hidden_def(_IO_wfile_seekoff)952 libc_hidden_def (_IO_wfile_seekoff)
953 
954 
955 size_t
956 _IO_wfile_xsputn (FILE *f, const void *data, size_t n)
957 {
958   const wchar_t *s = (const wchar_t *) data;
959   size_t to_do = n;
960   int must_flush = 0;
961   size_t count;
962 
963   if (n <= 0)
964     return 0;
965   /* This is an optimized implementation.
966      If the amount to be written straddles a block boundary
967      (or the filebuf is unbuffered), use sys_write directly. */
968 
969   /* First figure out how much space is available in the buffer. */
970   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
971   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
972     {
973       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
974       if (count >= n)
975 	{
976 	  const wchar_t *p;
977 	  for (p = s + n; p > s; )
978 	    {
979 	      if (*--p == L'\n')
980 		{
981 		  count = p - s + 1;
982 		  must_flush = 1;
983 		  break;
984 		}
985 	    }
986 	}
987     }
988   /* Then fill the buffer. */
989   if (count > 0)
990     {
991       if (count > to_do)
992 	count = to_do;
993       if (count > 20)
994 	{
995 	  f->_wide_data->_IO_write_ptr =
996 	    __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
997 	  s += count;
998 	}
999       else
1000 	{
1001 	  wchar_t *p = f->_wide_data->_IO_write_ptr;
1002 	  int i = (int) count;
1003 	  while (--i >= 0)
1004 	    *p++ = *s++;
1005 	  f->_wide_data->_IO_write_ptr = p;
1006 	}
1007       to_do -= count;
1008     }
1009   if (to_do > 0)
1010     to_do -= _IO_wdefault_xsputn (f, s, to_do);
1011   if (must_flush
1012       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1013     _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1014 		   f->_wide_data->_IO_write_ptr
1015 		   - f->_wide_data->_IO_write_base);
1016 
1017   return n - to_do;
1018 }
1019 libc_hidden_def (_IO_wfile_xsputn)
1020 
1021 
1022 const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1023 {
1024   JUMP_INIT_DUMMY,
1025   JUMP_INIT(finish, _IO_new_file_finish),
1026   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1027   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1028   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1029   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1030   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1031   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1032   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1033   JUMP_INIT(seekpos, _IO_default_seekpos),
1034   JUMP_INIT(setbuf, _IO_new_file_setbuf),
1035   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1036   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1037   JUMP_INIT(read, _IO_file_read),
1038   JUMP_INIT(write, _IO_new_file_write),
1039   JUMP_INIT(seek, _IO_file_seek),
1040   JUMP_INIT(close, _IO_file_close),
1041   JUMP_INIT(stat, _IO_file_stat),
1042   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1043   JUMP_INIT(imbue, _IO_default_imbue)
1044 };
1045 libc_hidden_data_def (_IO_wfile_jumps)
1046 
1047 
1048 const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
1049 {
1050   JUMP_INIT_DUMMY,
1051   JUMP_INIT(finish, _IO_new_file_finish),
1052   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1053   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
1054   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1055   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1056   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1057   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1058   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1059   JUMP_INIT(seekpos, _IO_default_seekpos),
1060   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1061   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1062   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1063   JUMP_INIT(read, _IO_file_read),
1064   JUMP_INIT(write, _IO_new_file_write),
1065   JUMP_INIT(seek, _IO_file_seek),
1066   JUMP_INIT(close, _IO_file_close_mmap),
1067   JUMP_INIT(stat, _IO_file_stat),
1068   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1069   JUMP_INIT(imbue, _IO_default_imbue)
1070 };
1071 
1072 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1073 {
1074   JUMP_INIT_DUMMY,
1075   JUMP_INIT(finish, _IO_new_file_finish),
1076   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1077   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1078   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1079   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1080   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1081   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1082   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1083   JUMP_INIT(seekpos, _IO_default_seekpos),
1084   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1085   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1086   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1087   JUMP_INIT(read, _IO_file_read),
1088   JUMP_INIT(write, _IO_new_file_write),
1089   JUMP_INIT(seek, _IO_file_seek),
1090   JUMP_INIT(close, _IO_file_close),
1091   JUMP_INIT(stat, _IO_file_stat),
1092   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1093   JUMP_INIT(imbue, _IO_default_imbue)
1094 };
1095