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