1 /* Copyright (C) 1993-2021 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     {
417       /* Allocate a buffer if needed. */
418       if (f->_wide_data->_IO_write_base == 0)
419 	{
420 	  _IO_wdoallocbuf (f);
421 	  _IO_free_wbackup_area (f);
422 	  _IO_wsetg (f, f->_wide_data->_IO_buf_base,
423 		     f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
424 
425 	  if (f->_IO_write_base == NULL)
426 	    {
427 	      _IO_doallocbuf (f);
428 	      _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
429 	    }
430 	}
431       else
432 	{
433 	  /* Otherwise must be currently reading.  If _IO_read_ptr
434 	     (and hence also _IO_read_end) is at the buffer end,
435 	     logically slide the buffer forwards one block (by setting
436 	     the read pointers to all point at the beginning of the
437 	     block).  This makes room for subsequent output.
438 	     Otherwise, set the read pointers to _IO_read_end (leaving
439 	     that alone, so it can continue to correspond to the
440 	     external position). */
441 	  if (f->_wide_data->_IO_read_ptr == f->_wide_data->_IO_buf_end)
442 	    {
443 	      f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
444 	      f->_wide_data->_IO_read_end = f->_wide_data->_IO_read_ptr =
445 		f->_wide_data->_IO_buf_base;
446 	    }
447 	}
448       f->_wide_data->_IO_write_ptr = f->_wide_data->_IO_read_ptr;
449       f->_wide_data->_IO_write_base = f->_wide_data->_IO_write_ptr;
450       f->_wide_data->_IO_write_end = f->_wide_data->_IO_buf_end;
451       f->_wide_data->_IO_read_base = f->_wide_data->_IO_read_ptr =
452 	f->_wide_data->_IO_read_end;
453 
454       f->_IO_write_ptr = f->_IO_read_ptr;
455       f->_IO_write_base = f->_IO_write_ptr;
456       f->_IO_write_end = f->_IO_buf_end;
457       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
458 
459       f->_flags |= _IO_CURRENTLY_PUTTING;
460       if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
461 	f->_wide_data->_IO_write_end = f->_wide_data->_IO_write_ptr;
462     }
463   if (wch == WEOF)
464     return _IO_do_flush (f);
465   if (f->_wide_data->_IO_write_ptr == f->_wide_data->_IO_buf_end)
466     /* Buffer is really full */
467     if (_IO_do_flush (f) == EOF)
468       return WEOF;
469   *f->_wide_data->_IO_write_ptr++ = wch;
470   if ((f->_flags & _IO_UNBUFFERED)
471       || ((f->_flags & _IO_LINE_BUF) && wch == L'\n'))
472     if (_IO_do_flush (f) == EOF)
473       return WEOF;
474   return wch;
475 }
libc_hidden_def(_IO_wfile_overflow)476 libc_hidden_def (_IO_wfile_overflow)
477 
478 wint_t
479 _IO_wfile_sync (FILE *fp)
480 {
481   ssize_t delta;
482   wint_t retval = 0;
483 
484   /*    char* ptr = cur_ptr(); */
485   if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
486     if (_IO_do_flush (fp))
487       return WEOF;
488   delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end;
489   if (delta != 0)
490     {
491       /* We have to find out how many bytes we have to go back in the
492 	 external buffer.  */
493       struct _IO_codecvt *cv = fp->_codecvt;
494       off64_t new_pos;
495 
496       int clen = __libio_codecvt_encoding (cv);
497 
498       if (clen > 0)
499 	/* It is easy, a fixed number of input bytes are used for each
500 	   wide character.  */
501 	delta *= clen;
502       else
503 	{
504 	  /* We have to find out the hard way how much to back off.
505 	     To do this we determine how much input we needed to
506 	     generate the wide characters up to the current reading
507 	     position.  */
508 	  int nread;
509 	  size_t wnread = (fp->_wide_data->_IO_read_ptr
510 			   - fp->_wide_data->_IO_read_base);
511 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
512 	  nread = __libio_codecvt_length (cv, &fp->_wide_data->_IO_state,
513 					  fp->_IO_read_base,
514 					  fp->_IO_read_end, wnread);
515 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
516 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
517 	}
518 
519       new_pos = _IO_SYSSEEK (fp, delta, 1);
520       if (new_pos != (off64_t) EOF)
521 	{
522 	  fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
523 	  fp->_IO_read_end = fp->_IO_read_ptr;
524 	}
525       else if (errno == ESPIPE)
526 	; /* Ignore error from unseekable devices. */
527       else
528 	retval = WEOF;
529     }
530   if (retval != WEOF)
531     fp->_offset = _IO_pos_BAD;
532   /* FIXME: Cleanup - can this be shared? */
533   /*    setg(base(), ptr, ptr); */
534   return retval;
535 }
libc_hidden_def(_IO_wfile_sync)536 libc_hidden_def (_IO_wfile_sync)
537 
538 /* Adjust the internal buffer pointers to reflect the state in the external
539    buffer.  The content between fp->_IO_read_base and fp->_IO_read_ptr is
540    assumed to be converted and available in the range
541    fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end.
542 
543    Returns 0 on success and -1 on error with the _IO_ERR_SEEN flag set.  */
544 static int
545 adjust_wide_data (FILE *fp, bool do_convert)
546 {
547   struct _IO_codecvt *cv = fp->_codecvt;
548 
549   int clen = __libio_codecvt_encoding (cv);
550 
551   /* Take the easy way out for constant length encodings if we don't need to
552      convert.  */
553   if (!do_convert && clen > 0)
554     {
555       fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
556 				       / clen);
557       goto done;
558     }
559 
560   enum __codecvt_result status;
561   const char *read_stop = (const char *) fp->_IO_read_base;
562   do
563     {
564 
565       fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
566       status = __libio_codecvt_in (cv, &fp->_wide_data->_IO_state,
567 				   fp->_IO_read_base, fp->_IO_read_ptr,
568 				   &read_stop,
569 				   fp->_wide_data->_IO_read_base,
570 				   fp->_wide_data->_IO_buf_end,
571 				   &fp->_wide_data->_IO_read_end);
572 
573       /* Should we return EILSEQ?  */
574       if (__glibc_unlikely (status == __codecvt_error))
575 	{
576 	  fp->_flags |= _IO_ERR_SEEN;
577 	  return -1;
578 	}
579     }
580   while (__builtin_expect (status == __codecvt_partial, 0));
581 
582 done:
583   /* Now seek to _IO_read_end to behave as if we have read it all in.  */
584   fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
585 
586   return 0;
587 }
588 
589 /* ftell{,o} implementation for wide mode.  Don't modify any state of the file
590    pointer while we try to get the current state of the stream except in one
591    case, which is when we have unflushed writes in append mode.  */
592 static off64_t
do_ftell_wide(FILE * fp)593 do_ftell_wide (FILE *fp)
594 {
595   off64_t result, offset = 0;
596 
597   /* No point looking for offsets in the buffer if it hasn't even been
598      allocated.  */
599   if (fp->_wide_data->_IO_buf_base != NULL)
600     {
601       const wchar_t *wide_read_base;
602       const wchar_t *wide_read_ptr;
603       const wchar_t *wide_read_end;
604       bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
605 			       > fp->_wide_data->_IO_write_base);
606 
607       bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
608 
609       /* When we have unflushed writes in append mode, seek to the end of the
610 	 file and record that offset.  This is the only time we change the file
611 	 stream state and it is safe since the file handle is active.  */
612       if (unflushed_writes && append_mode)
613 	{
614 	  result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
615 	  if (result == _IO_pos_BAD)
616 	    return EOF;
617 	  else
618 	    fp->_offset = result;
619 	}
620 
621       /* XXX For wide stream with backup store it is not very
622 	 reasonable to determine the offset.  The pushed-back
623 	 character might require a state change and we need not be
624 	 able to compute the initial state by reverse transformation
625 	 since there is no guarantee of symmetry.  So we don't even
626 	 try and return an error.  */
627       if (_IO_in_backup (fp))
628 	{
629 	  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
630 	    {
631 	      __set_errno (EINVAL);
632 	      return -1;
633 	    }
634 
635 	  /* Nothing in the backup store, so note the backed up pointers
636 	     without changing the state.  */
637 	  wide_read_base = fp->_wide_data->_IO_save_base;
638 	  wide_read_ptr = wide_read_base;
639 	  wide_read_end = fp->_wide_data->_IO_save_end;
640 	}
641       else
642 	{
643 	  wide_read_base = fp->_wide_data->_IO_read_base;
644 	  wide_read_ptr = fp->_wide_data->_IO_read_ptr;
645 	  wide_read_end = fp->_wide_data->_IO_read_end;
646 	}
647 
648       struct _IO_codecvt *cv = fp->_codecvt;
649       int clen = __libio_codecvt_encoding (cv);
650 
651       if (!unflushed_writes)
652 	{
653 	  if (clen > 0)
654 	    {
655 	      offset -= (wide_read_end - wide_read_ptr) * clen;
656 	      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
657 	    }
658 	  else
659 	    {
660 	      int nread;
661 
662 	      size_t delta = wide_read_ptr - wide_read_base;
663 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
664 	      nread = __libio_codecvt_length (cv, &state,
665 					      fp->_IO_read_base,
666 					      fp->_IO_read_end, delta);
667 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
668 	    }
669 	}
670       else
671 	{
672 	  if (clen > 0)
673 	    offset += (fp->_wide_data->_IO_write_ptr
674 		       - fp->_wide_data->_IO_write_base) * clen;
675 	  else
676 	    {
677 	      size_t delta = (fp->_wide_data->_IO_write_ptr
678 			      - fp->_wide_data->_IO_write_base);
679 
680 	      /* Allocate enough space for the conversion.  */
681 	      size_t outsize = delta * sizeof (wchar_t);
682 	      char *out = malloc (outsize);
683 	      char *outstop = out;
684 	      const wchar_t *in = fp->_wide_data->_IO_write_base;
685 
686 	      enum __codecvt_result status;
687 
688 	      __mbstate_t state = fp->_wide_data->_IO_last_state;
689 	      status = __libio_codecvt_out (cv, &state, in, in + delta, &in,
690 					    out, out + outsize, &outstop);
691 
692 	      /* We don't check for __codecvt_partial because it can be
693 		 returned on one of two conditions: either the output
694 		 buffer is full or the input sequence is incomplete.  We
695 		 take care to allocate enough buffer and our input
696 		 sequences must be complete since they are accepted as
697 		 wchar_t; if not, then that is an error.  */
698 	      if (__glibc_unlikely (status != __codecvt_ok))
699 		{
700 		  free (out);
701 		  return WEOF;
702 		}
703 
704 	      offset += outstop - out;
705 	      free (out);
706 	    }
707 
708 	  /* We don't trust _IO_read_end to represent the current file offset
709 	     when writing in append mode because the value would have to be
710 	     shifted to the end of the file during a flush.  Use the write base
711 	     instead, along with the new offset we got above when we did a seek
712 	     to the end of the file.  */
713 	  if (append_mode)
714 	    offset += fp->_IO_write_ptr - fp->_IO_write_base;
715 	  /* For all other modes, _IO_read_end represents the file offset.  */
716 	  else
717 	    offset += fp->_IO_write_ptr - fp->_IO_read_end;
718 	}
719     }
720 
721   if (fp->_offset != _IO_pos_BAD)
722     result = fp->_offset;
723   else
724     result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
725 
726   if (result == EOF)
727     return result;
728 
729   result += offset;
730 
731   if (result < 0)
732     {
733       __set_errno (EINVAL);
734       return EOF;
735     }
736 
737   return result;
738 }
739 
740 off64_t
_IO_wfile_seekoff(FILE * fp,off64_t offset,int dir,int mode)741 _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
742 {
743   off64_t result;
744   off64_t delta, new_offset;
745   long int count;
746 
747   /* Short-circuit into a separate function.  We don't want to mix any
748      functionality and we don't want to touch anything inside the FILE
749      object. */
750   if (mode == 0)
751     return do_ftell_wide (fp);
752 
753   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
754      offset of the underlying file must be exact.  */
755   int must_be_exact = ((fp->_wide_data->_IO_read_base
756 			== fp->_wide_data->_IO_read_end)
757 		       && (fp->_wide_data->_IO_write_base
758 			   == fp->_wide_data->_IO_write_ptr));
759 
760   bool was_writing = ((fp->_wide_data->_IO_write_ptr
761 		       > fp->_wide_data->_IO_write_base)
762 		      || _IO_in_put_mode (fp));
763 
764   /* Flush unwritten characters.
765      (This may do an unneeded write if we seek within the buffer.
766      But to be able to switch to reading, we would need to set
767      egptr to pptr.  That can't be done in the current design,
768      which assumes file_ptr() is eGptr.  Anyway, since we probably
769      end up flushing when we close(), it doesn't make much difference.)
770      FIXME: simulate mem-mapped files. */
771   if (was_writing && _IO_switch_to_wget_mode (fp))
772     return WEOF;
773 
774   if (fp->_wide_data->_IO_buf_base == NULL)
775     {
776       /* It could be that we already have a pushback buffer.  */
777       if (fp->_wide_data->_IO_read_base != NULL)
778 	{
779 	  free (fp->_wide_data->_IO_read_base);
780 	  fp->_flags &= ~_IO_IN_BACKUP;
781 	}
782       _IO_doallocbuf (fp);
783       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
784       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
785       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
786 		 fp->_wide_data->_IO_buf_base);
787       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
788 		 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
789     }
790 
791   switch (dir)
792     {
793       struct _IO_codecvt *cv;
794       int clen;
795 
796     case _IO_seek_cur:
797       /* Adjust for read-ahead (bytes is buffer).  To do this we must
798 	 find out which position in the external buffer corresponds to
799 	 the current position in the internal buffer.  */
800       cv = fp->_codecvt;
801       clen = __libio_codecvt_encoding (cv);
802 
803       if (mode != 0 || !was_writing)
804 	{
805 	  if (clen > 0)
806 	    {
807 	      offset -= (fp->_wide_data->_IO_read_end
808 			 - fp->_wide_data->_IO_read_ptr) * clen;
809 	      /* Adjust by readahead in external buffer.  */
810 	      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
811 	    }
812 	  else
813 	    {
814 	      int nread;
815 
816 	      delta = (fp->_wide_data->_IO_read_ptr
817 		       - fp->_wide_data->_IO_read_base);
818 	      fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
819 	      nread = __libio_codecvt_length (cv,
820 					      &fp->_wide_data->_IO_state,
821 					      fp->_IO_read_base,
822 					      fp->_IO_read_end, delta);
823 	      fp->_IO_read_ptr = fp->_IO_read_base + nread;
824 	      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
825 	      offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
826 	    }
827 	}
828 
829       if (fp->_offset == _IO_pos_BAD)
830 	goto dumb;
831 
832       /* Make offset absolute, assuming current pointer is file_ptr(). */
833       offset += fp->_offset;
834 
835       dir = _IO_seek_set;
836       break;
837     case _IO_seek_set:
838       break;
839     case _IO_seek_end:
840       {
841 	struct __stat64_t64 st;
842 	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
843 	  {
844 	    offset += st.st_size;
845 	    dir = _IO_seek_set;
846 	  }
847 	else
848 	  goto dumb;
849       }
850     }
851 
852   _IO_free_wbackup_area (fp);
853 
854   /* At this point, dir==_IO_seek_set. */
855 
856   /* If destination is within current buffer, optimize: */
857   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
858       && !_IO_in_backup (fp))
859     {
860       off64_t start_offset = (fp->_offset
861                               - (fp->_IO_read_end - fp->_IO_buf_base));
862       if (offset >= start_offset && offset < fp->_offset)
863 	{
864 	  _IO_setg (fp, fp->_IO_buf_base,
865 		    fp->_IO_buf_base + (offset - start_offset),
866 		    fp->_IO_read_end);
867 	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
868 	  _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
869 		     fp->_wide_data->_IO_buf_base,
870 		     fp->_wide_data->_IO_buf_base);
871 	  _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
872 		     fp->_wide_data->_IO_buf_base);
873 
874 	  if (adjust_wide_data (fp, false))
875 	    goto dumb;
876 
877 	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
878 	  goto resync;
879 	}
880     }
881 
882   if (fp->_flags & _IO_NO_READS)
883     goto dumb;
884 
885   /* Try to seek to a block boundary, to improve kernel page management. */
886   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
887   delta = offset - new_offset;
888   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
889     {
890       new_offset = offset;
891       delta = 0;
892     }
893   result = _IO_SYSSEEK (fp, new_offset, 0);
894   if (result < 0)
895     return EOF;
896   if (delta == 0)
897     count = 0;
898   else
899     {
900       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
901 			   (must_be_exact
902 			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
903       if (count < delta)
904 	{
905 	  /* We weren't allowed to read, but try to seek the remainder. */
906 	  offset = count == EOF ? delta : delta-count;
907 	  dir = _IO_seek_cur;
908 	  goto dumb;
909 	}
910     }
911   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
912 	    fp->_IO_buf_base + count);
913   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
914   _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
915 	     fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
916   _IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
917 
918   if (adjust_wide_data (fp, true))
919     goto dumb;
920 
921   fp->_offset = result + count;
922   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
923   return offset;
924  dumb:
925 
926   _IO_unsave_markers (fp);
927   result = _IO_SYSSEEK (fp, offset, dir);
928   if (result != EOF)
929     {
930       _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
931       fp->_offset = result;
932       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
933       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
934       _IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
935 		 fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
936       _IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
937 		 fp->_wide_data->_IO_buf_base);
938     }
939   return result;
940 
941 resync:
942   /* We need to do it since it is possible that the file offset in
943      the kernel may be changed behind our back. It may happen when
944      we fopen a file and then do a fork. One process may access the
945      file and the kernel file offset will be changed. */
946   if (fp->_offset >= 0)
947     _IO_SYSSEEK (fp, fp->_offset, 0);
948 
949   return offset;
950 }
libc_hidden_def(_IO_wfile_seekoff)951 libc_hidden_def (_IO_wfile_seekoff)
952 
953 
954 size_t
955 _IO_wfile_xsputn (FILE *f, const void *data, size_t n)
956 {
957   const wchar_t *s = (const wchar_t *) data;
958   size_t to_do = n;
959   int must_flush = 0;
960   size_t count;
961 
962   if (n <= 0)
963     return 0;
964   /* This is an optimized implementation.
965      If the amount to be written straddles a block boundary
966      (or the filebuf is unbuffered), use sys_write directly. */
967 
968   /* First figure out how much space is available in the buffer. */
969   count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr;
970   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
971     {
972       count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr;
973       if (count >= n)
974 	{
975 	  const wchar_t *p;
976 	  for (p = s + n; p > s; )
977 	    {
978 	      if (*--p == L'\n')
979 		{
980 		  count = p - s + 1;
981 		  must_flush = 1;
982 		  break;
983 		}
984 	    }
985 	}
986     }
987   /* Then fill the buffer. */
988   if (count > 0)
989     {
990       if (count > to_do)
991 	count = to_do;
992       if (count > 20)
993 	{
994 	  f->_wide_data->_IO_write_ptr =
995 	    __wmempcpy (f->_wide_data->_IO_write_ptr, s, count);
996 	  s += count;
997 	}
998       else
999 	{
1000 	  wchar_t *p = f->_wide_data->_IO_write_ptr;
1001 	  int i = (int) count;
1002 	  while (--i >= 0)
1003 	    *p++ = *s++;
1004 	  f->_wide_data->_IO_write_ptr = p;
1005 	}
1006       to_do -= count;
1007     }
1008   if (to_do > 0)
1009     to_do -= _IO_wdefault_xsputn (f, s, to_do);
1010   if (must_flush
1011       && f->_wide_data->_IO_write_ptr != f->_wide_data->_IO_write_base)
1012     _IO_wdo_write (f, f->_wide_data->_IO_write_base,
1013 		   f->_wide_data->_IO_write_ptr
1014 		   - f->_wide_data->_IO_write_base);
1015 
1016   return n - to_do;
1017 }
1018 libc_hidden_def (_IO_wfile_xsputn)
1019 
1020 
1021 const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
1022 {
1023   JUMP_INIT_DUMMY,
1024   JUMP_INIT(finish, _IO_new_file_finish),
1025   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1026   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
1027   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1028   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1029   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1030   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1031   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1032   JUMP_INIT(seekpos, _IO_default_seekpos),
1033   JUMP_INIT(setbuf, _IO_new_file_setbuf),
1034   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1035   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1036   JUMP_INIT(read, _IO_file_read),
1037   JUMP_INIT(write, _IO_new_file_write),
1038   JUMP_INIT(seek, _IO_file_seek),
1039   JUMP_INIT(close, _IO_file_close),
1040   JUMP_INIT(stat, _IO_file_stat),
1041   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1042   JUMP_INIT(imbue, _IO_default_imbue)
1043 };
1044 libc_hidden_data_def (_IO_wfile_jumps)
1045 
1046 
1047 const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
1048 {
1049   JUMP_INIT_DUMMY,
1050   JUMP_INIT(finish, _IO_new_file_finish),
1051   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1052   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
1053   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1054   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1055   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1056   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1057   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1058   JUMP_INIT(seekpos, _IO_default_seekpos),
1059   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1060   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1061   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1062   JUMP_INIT(read, _IO_file_read),
1063   JUMP_INIT(write, _IO_new_file_write),
1064   JUMP_INIT(seek, _IO_file_seek),
1065   JUMP_INIT(close, _IO_file_close_mmap),
1066   JUMP_INIT(stat, _IO_file_stat),
1067   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1068   JUMP_INIT(imbue, _IO_default_imbue)
1069 };
1070 
1071 const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
1072 {
1073   JUMP_INIT_DUMMY,
1074   JUMP_INIT(finish, _IO_new_file_finish),
1075   JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
1076   JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
1077   JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
1078   JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1079   JUMP_INIT(xsputn, _IO_wfile_xsputn),
1080   JUMP_INIT(xsgetn, _IO_file_xsgetn),
1081   JUMP_INIT(seekoff, _IO_wfile_seekoff),
1082   JUMP_INIT(seekpos, _IO_default_seekpos),
1083   JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
1084   JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
1085   JUMP_INIT(doallocate, _IO_wfile_doallocate),
1086   JUMP_INIT(read, _IO_file_read),
1087   JUMP_INIT(write, _IO_new_file_write),
1088   JUMP_INIT(seek, _IO_file_seek),
1089   JUMP_INIT(close, _IO_file_close),
1090   JUMP_INIT(stat, _IO_file_stat),
1091   JUMP_INIT(showmanyc, _IO_default_showmanyc),
1092   JUMP_INIT(imbue, _IO_default_imbue)
1093 };
1094