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