Increase timeout of libio/tst-readline
[platform/upstream/glibc.git] / libio / oldfileops.c
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
97 void
98 attribute_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
121 void
122 attribute_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
129 int
130 attribute_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
157 void
158 attribute_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
170 FILE *
171 attribute_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
217 FILE *
218 attribute_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
235 FILE *
236 attribute_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
249 static 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
254 int
255 attribute_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
262 static int
263 attribute_compat_text_section
264 old_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
292 int
293 attribute_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
355 int
356 attribute_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
405 int
406 attribute_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
437 off64_t
438 attribute_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
605 resync:
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
616 ssize_t
617 attribute_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
638 size_t
639 attribute_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
724 const 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
746 compat_symbol (libc, _IO_old_do_write, _IO_do_write, GLIBC_2_0);
747 compat_symbol (libc, _IO_old_file_attach, _IO_file_attach, GLIBC_2_0);
748 compat_symbol (libc, _IO_old_file_close_it, _IO_file_close_it, GLIBC_2_0);
749 compat_symbol (libc, _IO_old_file_finish, _IO_file_finish, GLIBC_2_0);
750 compat_symbol (libc, _IO_old_file_fopen, _IO_file_fopen, GLIBC_2_0);
751 compat_symbol (libc, _IO_old_file_init, _IO_file_init, GLIBC_2_0);
752 compat_symbol (libc, _IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2_0);
753 compat_symbol (libc, _IO_old_file_sync, _IO_file_sync, GLIBC_2_0);
754 compat_symbol (libc, _IO_old_file_overflow, _IO_file_overflow, GLIBC_2_0);
755 compat_symbol (libc, _IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2_0);
756 compat_symbol (libc, _IO_old_file_underflow, _IO_file_underflow, GLIBC_2_0);
757 compat_symbol (libc, _IO_old_file_write, _IO_file_write, GLIBC_2_0);
758 compat_symbol (libc, _IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2_0);
759
760 #endif