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