1/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Written by Per Bothner <bothner@cygnus.com>.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>.
18
19 As a special exception, if you link the code in this file with
20 files compiled with a GNU compiler to produce an executable,
21 that does not cause the resulting executable to be covered by
22 the GNU Lesser General Public License. This exception does not
23 however invalidate any other reasons why the executable file
24 might be covered by the GNU Lesser General Public License.
25 This exception applies to code released by its copyright holders
26 in files containing the exception. */
27
28/* This is a compatibility file. If we don't build the libc with
29 versioning don't compile this file. */
30#include <shlib-compat.h>
31#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
32
33#define _IO_USE_OLD_IO_FILE
34#include "libioP.h"
35#include <fcntl.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <string.h>
39#include <errno.h>
40#include <stdlib.h>
41#include <unistd.h>
42
43/* An fstream can be in at most one of put mode, get mode, or putback mode.
44 Putback mode is a variant of get mode.
45
46 In a filebuf, there is only one current position, instead of two
47 separate get and put pointers. In get mode, the current position
48 is that of gptr(); in put mode that of pptr().
49
50 The position in the buffer that corresponds to the position
51 in external file system is normally _IO_read_end, except in putback
52 mode, when it is _IO_save_end.
53 If the field _fb._offset is >= 0, it gives the offset in
54 the file as a whole corresponding to eGptr(). (?)
55
56 PUT MODE:
57 If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
58 and _IO_read_base are equal to each other. These are usually equal
59 to _IO_buf_base, though not necessarily if we have switched from
60 get mode to put mode. (The reason is to maintain the invariant
61 that _IO_read_end corresponds to the external file position.)
62 _IO_write_base is non-NULL and usually equal to _IO_buf_base.
63 We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
64 The un-flushed character are those between _IO_write_base and _IO_write_ptr.
65
66 GET MODE:
67 If a filebuf is in get or putback mode, eback() != egptr().
68 In get mode, the unread characters are between gptr() and egptr().
69 The OS file position corresponds to that of egptr().
70
71 PUTBACK MODE:
72 Putback mode is used to remember "excess" characters that have
73 been sputbackc'd in a separate putback buffer.
74 In putback mode, the get buffer points to the special putback buffer.
75 The unread characters are the characters between gptr() and egptr()
76 in the putback buffer, as well as the area between save_gptr()
77 and save_egptr(), which point into the original reserve buffer.
78 (The pointers save_gptr() and save_egptr() are the values
79 of gptr() and egptr() at the time putback mode was entered.)
80 The OS position corresponds to that of save_egptr().
81
82 LINE BUFFERED OUTPUT:
83 During line buffered output, _IO_write_base==base() && epptr()==base().
84 However, ptr() may be anywhere between base() and ebuf().
85 This forces a call to filebuf::overflow(int C) on every put.
86 If there is more space in the buffer, and C is not a '\n',
87 then C is inserted, and pptr() incremented.
88
89 UNBUFFERED STREAMS:
90 If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
91*/
92
93#define CLOSED_FILEBUF_FLAGS \
94 (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
95
96
97void
98attribute_compat_text_section
99_IO_old_file_init_internal (struct _IO_FILE_plus *fp)
100{
101 /* POSIX.1 allows another file handle to be used to change the position
102 of our file descriptor. Hence we actually don't know the actual
103 position before we do the first fseek (and until a following fflush). */
104 fp->file._old_offset = _IO_pos_BAD;
105 fp->file._flags |= CLOSED_FILEBUF_FLAGS;
106
107 _IO_link_in (fp);
108 fp->file._vtable_offset = ((int) sizeof (struct _IO_FILE)
109 - (int) sizeof (struct _IO_FILE_complete));
110 fp->file._fileno = -1;
111
112 if (__builtin_expect (&_IO_stdin_used != NULL, 1)
113 || (fp != (struct _IO_FILE_plus *) _IO_stdin
114 && fp != (struct _IO_FILE_plus *) _IO_stdout
115 && fp != (struct _IO_FILE_plus *) _IO_stderr))
116 /* The object is dynamically allocated and large enough. Initialize
117 the _mode element as well. */
118 ((struct _IO_FILE_complete *) fp)->_mode = -1;
119}
120
121void
122attribute_compat_text_section
123_IO_old_file_init (struct _IO_FILE_plus *fp)
124{
125 IO_set_accept_foreign_vtables (&_IO_vtable_check);
126 _IO_old_file_init_internal (fp);
127}
128
129int
130attribute_compat_text_section
131_IO_old_file_close_it (FILE *fp)
132{
133 int write_status, close_status;
134 if (!_IO_file_is_open (fp))
135 return EOF;
136
137 write_status = _IO_old_do_flush (fp);
138
139 _IO_unsave_markers (fp);
140
141 close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0
142 ? _IO_SYSCLOSE (fp) : 0);
143
144 /* Free buffer. */
145 _IO_setb (fp, NULL, NULL, 0);
146 _IO_setg (fp, NULL, NULL, NULL);
147 _IO_setp (fp, NULL, NULL);
148
149 _IO_un_link ((struct _IO_FILE_plus *) fp);
150 fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
151 fp->_fileno = -1;
152 fp->_old_offset = _IO_pos_BAD;
153
154 return close_status ? close_status : write_status;
155}
156
157void
158attribute_compat_text_section
159_IO_old_file_finish (FILE *fp, int dummy)
160{
161 if (_IO_file_is_open (fp))
162 {
163 _IO_old_do_flush (fp);
164 if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
165 _IO_SYSCLOSE (fp);
166 }
167 _IO_default_finish (fp, 0);
168}
169
170FILE *
171attribute_compat_text_section
172_IO_old_file_fopen (FILE *fp, const char *filename, const char *mode)
173{
174 int oflags = 0, omode;
175 int read_write, fdesc;
176 int oprot = 0666;
177 if (_IO_file_is_open (fp))
178 return 0;
179 switch (*mode++)
180 {
181 case 'r':
182 omode = O_RDONLY;
183 read_write = _IO_NO_WRITES;
184 break;
185 case 'w':
186 omode = O_WRONLY;
187 oflags = O_CREAT|O_TRUNC;
188 read_write = _IO_NO_READS;
189 break;
190 case 'a':
191 omode = O_WRONLY;
192 oflags = O_CREAT|O_APPEND;
193 read_write = _IO_NO_READS|_IO_IS_APPENDING;
194 break;
195 default:
196 __set_errno (EINVAL);
197 return NULL;
198 }
199 if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
200 {
201 omode = O_RDWR;
202 read_write &= _IO_IS_APPENDING;
203 }
204 fdesc = __open (filename, omode|oflags, oprot);
205 if (fdesc < 0)
206 return NULL;
207 fp->_fileno = fdesc;
208 _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
209 if (read_write & _IO_IS_APPENDING)
210 if (_IO_SEEKOFF (fp, (off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
211 == _IO_pos_BAD && errno != ESPIPE)
212 return NULL;
213 _IO_link_in ((struct _IO_FILE_plus *) fp);
214 return fp;
215}
216
217FILE *
218attribute_compat_text_section
219_IO_old_file_attach (FILE *fp, int fd)
220{
221 if (_IO_file_is_open (fp))
222 return NULL;
223 fp->_fileno = fd;
224 fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
225 fp->_flags |= _IO_DELETE_DONT_CLOSE;
226 /* Get the current position of the file. */
227 /* We have to do that since that may be junk. */
228 fp->_old_offset = _IO_pos_BAD;
229 if (_IO_SEEKOFF (fp, (off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
230 == _IO_pos_BAD && errno != ESPIPE)
231 return NULL;
232 return fp;
233}
234
235FILE *
236attribute_compat_text_section
237_IO_old_file_setbuf (FILE *fp, char *p, ssize_t len)
238{
239 if (_IO_default_setbuf (fp, p, len) == NULL)
240 return NULL;
241
242 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
243 = fp->_IO_buf_base;
244 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
245
246 return fp;
247}
248
249static int old_do_write (FILE *, const char *, size_t);
250
251/* Write TO_DO bytes from DATA to FP.
252 Then mark FP as having empty buffers. */
253
254int
255attribute_compat_text_section
256_IO_old_do_write (FILE *fp, const char *data, size_t to_do)
257{
258 return (to_do == 0 || (size_t) old_do_write (fp, data, to_do) == to_do)
259 ? 0 : EOF;
260}
261
262static int
263attribute_compat_text_section
264old_do_write (FILE *fp, const char *data, size_t to_do)
265{
266 size_t count;
267 if (fp->_flags & _IO_IS_APPENDING)
268 /* On a system without a proper O_APPEND implementation,
269 you would need to sys_seek(0, SEEK_END) here, but is
270 not needed nor desirable for Unix- or Posix-like systems.
271 Instead, just indicate that offset (before and after) is
272 unpredictable. */
273 fp->_old_offset = _IO_pos_BAD;
274 else if (fp->_IO_read_end != fp->_IO_write_base)
275 {
276 off_t new_pos
277 = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
278 if (new_pos == _IO_pos_BAD)
279 return 0;
280 fp->_old_offset = new_pos;
281 }
282 count = _IO_SYSWRITE (fp, data, to_do);
283 if (fp->_cur_column && count)
284 fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
285 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
286 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
287 fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
288 ? fp->_IO_buf_base : fp->_IO_buf_end);
289 return count;
290}
291
292int
293attribute_compat_text_section
294_IO_old_file_underflow (FILE *fp)
295{
296 ssize_t count;
297
298 /* C99 requires EOF to be "sticky". */
299 if (fp->_flags & _IO_EOF_SEEN)
300 return EOF;
301
302 if (fp->_flags & _IO_NO_READS)
303 {
304 fp->_flags |= _IO_ERR_SEEN;
305 __set_errno (EBADF);
306 return EOF;
307 }
308 if (fp->_IO_read_ptr < fp->_IO_read_end)
309 return *(unsigned char *) fp->_IO_read_ptr;
310
311 if (fp->_IO_buf_base == NULL)
312 {
313 /* Maybe we already have a push back pointer. */
314 if (fp->_IO_save_base != NULL)
315 {
316 free (fp->_IO_save_base);
317 fp->_flags &= ~_IO_IN_BACKUP;
318 }
319 _IO_doallocbuf (fp);
320 }
321
322 /* Flush all line buffered files before reading. */
323 /* FIXME This can/should be moved to genops ?? */
324 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
325 _IO_flush_all_linebuffered ();
326
327 _IO_switch_to_get_mode (fp);
328
329 /* This is very tricky. We have to adjust those
330 pointers before we call _IO_SYSREAD () since
331 we may longjump () out while waiting for
332 input. Those pointers may be screwed up. H.J. */
333 fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
334 fp->_IO_read_end = fp->_IO_buf_base;
335 fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
336 = fp->_IO_buf_base;
337
338 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
339 fp->_IO_buf_end - fp->_IO_buf_base);
340 if (count <= 0)
341 {
342 if (count == 0)
343 fp->_flags |= _IO_EOF_SEEN;
344 else
345 fp->_flags |= _IO_ERR_SEEN, count = 0;
346 }
347 fp->_IO_read_end += count;
348 if (count == 0)
349 return EOF;
350 if (fp->_old_offset != _IO_pos_BAD)
351 _IO_pos_adjust (fp->_old_offset, count);
352 return *(unsigned char *) fp->_IO_read_ptr;
353}
354
355int
356attribute_compat_text_section
357_IO_old_file_overflow (FILE *f, int ch)
358{
359 if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
360 {
361 f->_flags |= _IO_ERR_SEEN;
362 __set_errno (EBADF);
363 return EOF;
364 }
365 /* If currently reading or no buffer allocated. */
366 if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
367 {
368 /* Allocate a buffer if needed. */
369 if (f->_IO_write_base == 0)
370 {
371 _IO_doallocbuf (f);
372 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
373 }
374 /* Otherwise must be currently reading.
375 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
376 logically slide the buffer forwards one block (by setting the
377 read pointers to all point at the beginning of the block). This
378 makes room for subsequent output.
379 Otherwise, set the read pointers to _IO_read_end (leaving that
380 alone, so it can continue to correspond to the external position). */
381 if (f->_IO_read_ptr == f->_IO_buf_end)
382 f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
383 f->_IO_write_ptr = f->_IO_read_ptr;
384 f->_IO_write_base = f->_IO_write_ptr;
385 f->_IO_write_end = f->_IO_buf_end;
386 f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
387
388 if (f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
389 f->_IO_write_end = f->_IO_write_ptr;
390 f->_flags |= _IO_CURRENTLY_PUTTING;
391 }
392 if (ch == EOF)
393 return _IO_old_do_flush (f);
394 if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
395 if (_IO_old_do_flush (f) == EOF)
396 return EOF;
397 *f->_IO_write_ptr++ = ch;
398 if ((f->_flags & _IO_UNBUFFERED)
399 || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
400 if (_IO_old_do_flush (f) == EOF)
401 return EOF;
402 return (unsigned char) ch;
403}
404
405int
406attribute_compat_text_section
407_IO_old_file_sync (FILE *fp)
408{
409 ssize_t delta;
410 int retval = 0;
411
412 /* char* ptr = cur_ptr(); */
413 if (fp->_IO_write_ptr > fp->_IO_write_base)
414 if (_IO_old_do_flush(fp)) return EOF;
415 delta = fp->_IO_read_ptr - fp->_IO_read_end;
416 if (delta != 0)
417 {
418#ifdef TODO
419 if (_IO_in_backup (fp))
420 delta -= eGptr () - Gbase ();
421#endif
422 off_t new_pos = _IO_SYSSEEK (fp, delta, 1);
423 if (new_pos != (off_t) EOF)
424 fp->_IO_read_end = fp->_IO_read_ptr;
425 else if (errno == ESPIPE)
426 ; /* Ignore error from unseekable devices. */
427 else
428 retval = EOF;
429 }
430 if (retval != EOF)
431 fp->_old_offset = _IO_pos_BAD;
432 /* FIXME: Cleanup - can this be shared? */
433 /* setg(base(), ptr, ptr); */
434 return retval;
435}
436
437off64_t
438attribute_compat_text_section
439_IO_old_file_seekoff (FILE *fp, off64_t offset, int dir, int mode)
440{
441 off_t result;
442 off64_t delta, new_offset;
443 long count;
444 /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
445 offset of the underlying file must be exact. */
446 int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
447 && fp->_IO_write_base == fp->_IO_write_ptr);
448
449 if (mode == 0)
450 dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
451
452 /* Flush unwritten characters.
453 (This may do an unneeded write if we seek within the buffer.
454 But to be able to switch to reading, we would need to set
455 egptr to pptr. That can't be done in the current design,
456 which assumes file_ptr() is eGptr. Anyway, since we probably
457 end up flushing when we close(), it doesn't make much difference.)
458 FIXME: simulate mem-mapped files. */
459
460 if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
461 if (_IO_switch_to_get_mode (fp))
462 return EOF;
463
464 if (fp->_IO_buf_base == NULL)
465 {
466 /* It could be that we already have a pushback buffer. */
467 if (fp->_IO_read_base != NULL)
468 {
469 free (fp->_IO_read_base);
470 fp->_flags &= ~_IO_IN_BACKUP;
471 }
472 _IO_doallocbuf (fp);
473 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
474 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
475 }
476
477 switch (dir)
478 {
479 case _IO_seek_cur:
480 /* Adjust for read-ahead (bytes is buffer). */
481 offset -= fp->_IO_read_end - fp->_IO_read_ptr;
482 if (fp->_old_offset == _IO_pos_BAD)
483 goto dumb;
484 /* Make offset absolute, assuming current pointer is file_ptr(). */
485 offset += fp->_old_offset;
486
487 dir = _IO_seek_set;
488 break;
489 case _IO_seek_set:
490 break;
491 case _IO_seek_end:
492 {
493 struct stat64 st;
494 if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
495 {
496 offset += st.st_size;
497 dir = _IO_seek_set;
498 }
499 else
500 goto dumb;
501 }
502 }
503 /* At this point, dir==_IO_seek_set. */
504
505 /* If we are only interested in the current position we've found it now. */
506 if (mode == 0)
507 return offset;
508
509 /* If destination is within current buffer, optimize: */
510 if (fp->_old_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
511 && !_IO_in_backup (fp))
512 {
513 /* Offset relative to start of main get area. */
514 off_t rel_offset = (offset - fp->_old_offset
515 + (fp->_IO_read_end - fp->_IO_read_base));
516 if (rel_offset >= 0)
517 {
518 if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
519 {
520 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
521 fp->_IO_read_end);
522 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
523 {
524 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
525 goto resync;
526 }
527 }
528#ifdef TODO
529 /* If we have streammarkers, seek forward by reading ahead. */
530 if (_IO_have_markers (fp))
531 {
532 int to_skip = rel_offset
533 - (fp->_IO_read_ptr - fp->_IO_read_base);
534 if (ignore (to_skip) != to_skip)
535 goto dumb;
536 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
537 goto resync;
538 }
539#endif
540 }
541#ifdef TODO
542 if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
543 {
544 if (!_IO_in_backup (fp))
545 _IO_switch_to_backup_area (fp);
546 gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
547 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
548 goto resync;
549 }
550#endif
551 }
552
553#ifdef TODO
554 _IO_unsave_markers (fp);
555#endif
556
557 if (fp->_flags & _IO_NO_READS)
558 goto dumb;
559
560 /* Try to seek to a block boundary, to improve kernel page management. */
561 new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
562 delta = offset - new_offset;
563 if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
564 {
565 new_offset = offset;
566 delta = 0;
567 }
568 result = _IO_SYSSEEK (fp, new_offset, 0);
569 if (result < 0)
570 return EOF;
571 if (delta == 0)
572 count = 0;
573 else
574 {
575 count = _IO_SYSREAD (fp, fp->_IO_buf_base,
576 (must_be_exact
577 ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
578 if (count < delta)
579 {
580 /* We weren't allowed to read, but try to seek the remainder. */
581 offset = count == EOF ? delta : delta-count;
582 dir = _IO_seek_cur;
583 goto dumb;
584 }
585 }
586 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
587 fp->_IO_buf_base + count);
588 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
589 fp->_old_offset = result + count;
590 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
591 return offset;
592 dumb:
593
594 _IO_unsave_markers (fp);
595 result = _IO_SYSSEEK (fp, offset, dir);
596 if (result != EOF)
597 {
598 _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
599 fp->_old_offset = result;
600 _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
601 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
602 }
603 return result;
604
605resync:
606 /* We need to do it since it is possible that the file offset in
607 the kernel may be changed behind our back. It may happen when
608 we fopen a file and then do a fork. One process may access the
609 file and the kernel file offset will be changed. */
610 if (fp->_old_offset >= 0)
611 _IO_SYSSEEK (fp, fp->_old_offset, 0);
612
613 return offset;
614}
615
616ssize_t
617attribute_compat_text_section
618_IO_old_file_write (FILE *f, const void *data, ssize_t n)
619{
620 ssize_t to_do = n;
621 while (to_do > 0)
622 {
623 ssize_t count = __write (f->_fileno, data, to_do);
624 if (count == EOF)
625 {
626 f->_flags |= _IO_ERR_SEEN;
627 break;
628 }
629 to_do -= count;
630 data = (void *) ((char *) data + count);
631 }
632 n -= to_do;
633 if (f->_old_offset >= 0)
634 f->_old_offset += n;
635 return n;
636}
637
638size_t
639attribute_compat_text_section
640_IO_old_file_xsputn (FILE *f, const void *data, size_t n)
641{
642 const char *s = (char *) data;
643 size_t to_do = n;
644 int must_flush = 0;
645 size_t count = 0;
646
647 if (n <= 0)
648 return 0;
649 /* This is an optimized implementation.
650 If the amount to be written straddles a block boundary
651 (or the filebuf is unbuffered), use sys_write directly. */
652
653 /* First figure out how much space is available in the buffer. */
654 if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
655 {
656 count = f->_IO_buf_end - f->_IO_write_ptr;
657 if (count >= n)
658 {
659 const char *p;
660 for (p = s + n; p > s; )
661 {
662 if (*--p == '\n')
663 {
664 count = p - s + 1;
665 must_flush = 1;
666 break;
667 }
668 }
669 }
670 }
671 else if (f->_IO_write_end > f->_IO_write_ptr)
672 count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
673
674 /* Then fill the buffer. */
675 if (count > 0)
676 {
677 if (count > to_do)
678 count = to_do;
679 if (count > 20)
680 {
681 f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
682 s += count;
683 }
684 else
685 {
686 char *p = f->_IO_write_ptr;
687 int i = (int) count;
688 while (--i >= 0)
689 *p++ = *s++;
690 f->_IO_write_ptr = p;
691 }
692 to_do -= count;
693 }
694 if (to_do + must_flush > 0)
695 {
696 size_t block_size, do_write;
697 /* Next flush the (full) buffer. */
698 if (__overflow (f, EOF) == EOF)
699 return to_do == 0 ? EOF : n - to_do;
700
701 /* Try to maintain alignment: write a whole number of blocks.
702 dont_write is what gets left over. */
703 block_size = f->_IO_buf_end - f->_IO_buf_base;
704 do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
705
706 if (do_write)
707 {
708 count = old_do_write (f, s, do_write);
709 to_do -= count;
710 if (count < do_write)
711 return n - to_do;
712 }
713
714 /* Now write out the remainder. Normally, this will fit in the
715 buffer, but it's somewhat messier for line-buffered files,
716 so we let _IO_default_xsputn handle the general case. */
717 if (to_do)
718 to_do -= _IO_default_xsputn (f, s+do_write, to_do);
719 }
720 return n - to_do;
721}
722
723
724const struct _IO_jump_t _IO_old_file_jumps libio_vtable =
725{
726 JUMP_INIT_DUMMY,
727 JUMP_INIT(finish, _IO_old_file_finish),
728 JUMP_INIT(overflow, _IO_old_file_overflow),
729 JUMP_INIT(underflow, _IO_old_file_underflow),
730 JUMP_INIT(uflow, _IO_default_uflow),
731 JUMP_INIT(pbackfail, _IO_default_pbackfail),
732 JUMP_INIT(xsputn, _IO_old_file_xsputn),
733 JUMP_INIT(xsgetn, _IO_default_xsgetn),
734 JUMP_INIT(seekoff, _IO_old_file_seekoff),
735 JUMP_INIT(seekpos, _IO_default_seekpos),
736 JUMP_INIT(setbuf, _IO_old_file_setbuf),
737 JUMP_INIT(sync, _IO_old_file_sync),
738 JUMP_INIT(doallocate, _IO_file_doallocate),
739 JUMP_INIT(read, _IO_file_read),
740 JUMP_INIT(write, _IO_old_file_write),
741 JUMP_INIT(seek, _IO_file_seek),
742 JUMP_INIT(close, _IO_file_close),
743 JUMP_INIT(stat, _IO_file_stat)
744};
745
746compat_symbol (libc, _IO_old_do_write, _IO_do_write, GLIBC_2_0);
747compat_symbol (libc, _IO_old_file_attach, _IO_file_attach, GLIBC_2_0);
748compat_symbol (libc, _IO_old_file_close_it, _IO_file_close_it, GLIBC_2_0);
749compat_symbol (libc, _IO_old_file_finish, _IO_file_finish, GLIBC_2_0);
750compat_symbol (libc, _IO_old_file_fopen, _IO_file_fopen, GLIBC_2_0);
751compat_symbol (libc, _IO_old_file_init, _IO_file_init, GLIBC_2_0);
752compat_symbol (libc, _IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2_0);
753compat_symbol (libc, _IO_old_file_sync, _IO_file_sync, GLIBC_2_0);
754compat_symbol (libc, _IO_old_file_overflow, _IO_file_overflow, GLIBC_2_0);
755compat_symbol (libc, _IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2_0);
756compat_symbol (libc, _IO_old_file_underflow, _IO_file_underflow, GLIBC_2_0);
757compat_symbol (libc, _IO_old_file_write, _IO_file_write, GLIBC_2_0);
758compat_symbol (libc, _IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2_0);
759
760#endif
761