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