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