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