1/* Copyright (C) 1993, 1995, 1997-1999, 2000 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#ifdef __STDC__
38#include <stdlib.h>
39#endif
40#if _LIBC
41# include "../wcsmbs/wcsmbsload.h"
42# include <shlib-compat.h>
43#endif
44#ifndef errno
45extern 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#else
59# define _IO_new_do_write _IO_do_write
60# define _IO_new_file_attach _IO_file_attach
61# define _IO_new_file_close_it _IO_file_close_it
62# define _IO_new_file_finish _IO_file_finish
63# define _IO_new_file_fopen _IO_file_fopen
64# define _IO_new_file_init _IO_file_init
65# define _IO_new_file_setbuf _IO_file_setbuf
66# define _IO_new_file_sync _IO_file_sync
67# define _IO_new_file_overflow _IO_file_overflow
68# define _IO_new_file_seekoff _IO_file_seekoff
69# define _IO_new_file_underflow _IO_file_underflow
70# define _IO_new_file_write _IO_file_write
71# define _IO_new_file_xsputn _IO_file_xsputn
72#endif
73
74/* An fstream can be in at most one of put mode, get mode, or putback mode.
75   Putback mode is a variant of get mode.
76
77   In a filebuf, there is only one current position, instead of two
78   separate get and put pointers.  In get mode, the current position
79   is that of gptr(); in put mode that of pptr().
80
81   The position in the buffer that corresponds to the position
82   in external file system is normally _IO_read_end, except in putback
83   mode, when it is _IO_save_end.
84   If the field _fb._offset is >= 0, it gives the offset in
85   the file as a whole corresponding to eGptr(). (?)
86
87   PUT MODE:
88   If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
89   and _IO_read_base are equal to each other.  These are usually equal
90   to _IO_buf_base, though not necessarily if we have switched from
91   get mode to put mode.  (The reason is to maintain the invariant
92   that _IO_read_end corresponds to the external file position.)
93   _IO_write_base is non-NULL and usually equal to _IO_base_base.
94   We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
95   The un-flushed character are those between _IO_write_base and _IO_write_ptr.
96
97   GET MODE:
98   If a filebuf is in get or putback mode, eback() != egptr().
99   In get mode, the unread characters are between gptr() and egptr().
100   The OS file position corresponds to that of egptr().
101
102   PUTBACK MODE:
103   Putback mode is used to remember "excess" characters that have
104   been sputbackc'd in a separate putback buffer.
105   In putback mode, the get buffer points to the special putback buffer.
106   The unread characters are the characters between gptr() and egptr()
107   in the putback buffer, as well as the area between save_gptr()
108   and save_egptr(), which point into the original reserve buffer.
109   (The pointers save_gptr() and save_egptr() are the values
110   of gptr() and egptr() at the time putback mode was entered.)
111   The OS position corresponds to that of save_egptr().
112
113   LINE BUFFERED OUTPUT:
114   During line buffered output, _IO_write_base==base() && epptr()==base().
115   However, ptr() may be anywhere between base() and ebuf().
116   This forces a call to filebuf::overflow(int C) on every put.
117   If there is more space in the buffer, and C is not a '\n',
118   then C is inserted, and pptr() incremented.
119
120   UNBUFFERED STREAMS:
121   If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
122*/
123
124#define CLOSED_FILEBUF_FLAGS \
125  (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
126
127
128void
129_IO_new_file_init (fp)
130     struct _IO_FILE_plus *fp;
131{
132  /* POSIX.1 allows another file handle to be used to change the position
133     of our file descriptor.  Hence we actually don't know the actual
134     position before we do the first fseek (and until a following fflush). */
135  fp->file._offset = _IO_pos_BAD;
136  fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;
137
138  _IO_link_in (fp);
139  fp->file._fileno = -1;
140}
141
142int
143_IO_new_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_do_flush (fp);
151
152  _IO_unsave_markers(fp);
153
154  close_status = _IO_SYSCLOSE (fp);
155
156  /* Free buffer. */
157  if (fp->_mode <= 0)
158    {
159      _IO_setb (fp, NULL, NULL, 0);
160      _IO_setg (fp, NULL, NULL, NULL);
161      _IO_setp (fp, NULL, NULL);
162    }
163#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
164  else
165    {
166      _IO_wsetb (fp, NULL, NULL, 0);
167      _IO_wsetg (fp, NULL, NULL, NULL);
168      _IO_wsetp (fp, NULL, NULL);
169    }
170#endif
171
172  _IO_un_link ((struct _IO_FILE_plus *) fp);
173  fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
174  fp->_fileno = -1;
175  fp->_offset = _IO_pos_BAD;
176
177  return close_status ? close_status : write_status;
178}
179
180void
181_IO_new_file_finish (fp, dummy)
182     _IO_FILE *fp;
183     int dummy;
184{
185  if (_IO_file_is_open (fp))
186    {
187      _IO_do_flush (fp);
188      if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
189	_IO_SYSCLOSE (fp);
190    }
191  _IO_default_finish (fp, 0);
192}
193
194#if defined __GNUC__ && __GNUC__ >= 2
195__inline__
196#endif
197_IO_FILE *
198_IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64)
199     _IO_FILE *fp;
200     const char *filename;
201     int posix_mode;
202     int prot;
203     int read_write;
204     int is32not64;
205{
206  int fdesc;
207#ifdef _G_OPEN64
208  fdesc = (is32not64
209	   ? open (filename, posix_mode, prot)
210	   : _G_OPEN64 (filename, posix_mode, prot));
211#else
212  fdesc = open (filename, posix_mode, prot);
213#endif
214  if (fdesc < 0)
215    return NULL;
216  fp->_fileno = fdesc;
217  _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
218  if (read_write & _IO_IS_APPENDING)
219    if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
220	== _IO_pos_BAD && errno != ESPIPE)
221      return NULL;
222  _IO_link_in ((struct _IO_FILE_plus *) fp);
223  return fp;
224}
225
226_IO_FILE *
227_IO_new_file_fopen (fp, filename, mode, is32not64)
228     _IO_FILE *fp;
229     const char *filename;
230     const char *mode;
231     int is32not64;
232{
233  int oflags = 0, omode;
234  int read_write;
235  int oprot = 0666;
236  int i;
237  _IO_FILE *result;
238#if _LIBC
239  const char *cs;
240#endif
241
242  if (_IO_file_is_open (fp))
243    return 0;
244  switch (*mode)
245    {
246    case 'r':
247      omode = O_RDONLY;
248      read_write = _IO_NO_WRITES;
249      break;
250    case 'w':
251      omode = O_WRONLY;
252      oflags = O_CREAT|O_TRUNC;
253      read_write = _IO_NO_READS;
254      break;
255    case 'a':
256      omode = O_WRONLY;
257      oflags = O_CREAT|O_APPEND;
258      read_write = _IO_NO_READS|_IO_IS_APPENDING;
259      break;
260    default:
261      __set_errno (EINVAL);
262      return NULL;
263    }
264  for (i = 1; i < 4; ++i)
265    {
266      switch (*++mode)
267	{
268	case '\0':
269	  break;
270	case '+':
271	  omode = O_RDWR;
272	  read_write &= _IO_IS_APPENDING;
273	  continue;
274	case 'x':
275	  oflags |= O_EXCL;
276	  continue;
277	case 'b':
278	default:
279	  /* Ignore.  */
280	  continue;
281	}
282      break;
283    }
284
285  result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
286			  is32not64);
287
288
289#if _LIBC
290  /* Test whether the mode string specifies the conversion.  */
291  cs = strstr (mode, ",ccs=");
292  if (cs != NULL)
293    {
294      /* Yep.  Load the appropriate conversions and set the orientation
295	 to wide.  */
296	struct gconv_fcts fcts;
297	struct _IO_codecvt *cc;
298
299	if (! _IO_CHECK_WIDE (fp) || __wcsmbs_named_conv (&fcts, cs + 5) != 0)
300	  {
301	    /* Something went wrong, we cannot load the conversion modules.
302	       This means we cannot proceed since the user explicitly asked
303	       for these.  */
304	    _IO_new_fclose (result);
305	    return NULL;
306	  }
307
308	cc = fp->_codecvt = &fp->_wide_data->_codecvt;
309
310	/* The functions are always the same.  */
311	*cc = __libio_codecvt;
312
313	cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed.  */
314	cc->__cd_in.__cd.__steps = fcts.towc;
315
316	cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
317	cc->__cd_in.__cd.__data[0].__internal_use = 1;
318	cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
319	cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
320
321	cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed.  */
322	cc->__cd_out.__cd.__steps = fcts.tomb;
323
324	cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
325	cc->__cd_out.__cd.__data[0].__internal_use = 1;
326	cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
327	cc->__cd_out.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
328
329	/* Set the mode now.  */
330	result->_mode = 1;
331    }
332#endif	/* GNU libc */
333
334  return result;
335}
336
337_IO_FILE *
338_IO_new_file_attach (fp, fd)
339     _IO_FILE *fp;
340     int fd;
341{
342  if (_IO_file_is_open (fp))
343    return NULL;
344  fp->_fileno = fd;
345  fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
346  fp->_flags |= _IO_DELETE_DONT_CLOSE;
347  /* Get the current position of the file. */
348  /* We have to do that since that may be junk. */
349  fp->_offset = _IO_pos_BAD;
350  if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
351      == _IO_pos_BAD && errno != ESPIPE)
352    return NULL;
353  return fp;
354}
355
356_IO_FILE *
357_IO_new_file_setbuf (fp, p, len)
358     _IO_FILE *fp;
359     char *p;
360     _IO_ssize_t len;
361{
362  if (_IO_default_setbuf (fp, p, len) == NULL)
363    return NULL;
364
365  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
366    = fp->_IO_buf_base;
367  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
368
369  return fp;
370}
371
372static int new_do_write __P ((_IO_FILE *, const char *, _IO_size_t));
373
374/* Write TO_DO bytes from DATA to FP.
375   Then mark FP as having empty buffers. */
376
377int
378_IO_new_do_write (fp, data, to_do)
379     _IO_FILE *fp;
380     const char *data;
381     _IO_size_t to_do;
382{
383  return (to_do == 0 || new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
384}
385
386static
387int
388new_do_write (fp, data, to_do)
389     _IO_FILE *fp;
390     const char *data;
391     _IO_size_t to_do;
392{
393  _IO_size_t count;
394  if (fp->_flags & _IO_IS_APPENDING)
395    /* On a system without a proper O_APPEND implementation,
396       you would need to sys_seek(0, SEEK_END) here, but is
397       is not needed nor desirable for Unix- or Posix-like systems.
398       Instead, just indicate that offset (before and after) is
399       unpredictable. */
400    fp->_offset = _IO_pos_BAD;
401  else if (fp->_IO_read_end != fp->_IO_write_base)
402    {
403      _IO_off64_t new_pos
404	= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
405      if (new_pos == _IO_pos_BAD)
406	return 0;
407      fp->_offset = new_pos;
408    }
409  count = _IO_SYSWRITE (fp, data, to_do);
410  if (fp->_cur_column && count)
411    fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
412  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
413  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
414  fp->_IO_write_end = (fp->_mode < 0
415		       && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
416		       ? fp->_IO_buf_base : fp->_IO_buf_end);
417  return count;
418}
419
420int
421_IO_new_file_underflow (fp)
422     _IO_FILE *fp;
423{
424  _IO_ssize_t count;
425#if 0
426  /* SysV does not make this test; take it out for compatibility */
427  if (fp->_flags & _IO_EOF_SEEN)
428    return (EOF);
429#endif
430
431  if (fp->_flags & _IO_NO_READS)
432    {
433      fp->_flags |= _IO_ERR_SEEN;
434      __set_errno (EBADF);
435      return EOF;
436    }
437  if (fp->_IO_read_ptr < fp->_IO_read_end)
438    return *(unsigned char *) fp->_IO_read_ptr;
439
440  if (fp->_IO_buf_base == NULL)
441    {
442      /* Maybe we already have a push back pointer.  */
443      if (fp->_IO_save_base != NULL)
444	{
445	  free (fp->_IO_save_base);
446	  fp->_flags &= ~_IO_IN_BACKUP;
447	}
448      _IO_doallocbuf (fp);
449    }
450
451  /* Flush all line buffered files before reading. */
452  /* FIXME This can/should be moved to genops ?? */
453  if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
454    _IO_flush_all_linebuffered ();
455
456  _IO_switch_to_get_mode (fp);
457
458  /* This is very tricky. We have to adjust those
459     pointers before we call _IO_SYSREAD () since
460     we may longjump () out while waiting for
461     input. Those pointers may be screwed up. H.J. */
462  fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
463  fp->_IO_read_end = fp->_IO_buf_base;
464  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
465    = fp->_IO_buf_base;
466
467  count = _IO_SYSREAD (fp, fp->_IO_buf_base,
468		       fp->_IO_buf_end - fp->_IO_buf_base);
469  if (count <= 0)
470    {
471      if (count == 0)
472	fp->_flags |= _IO_EOF_SEEN;
473      else
474	fp->_flags |= _IO_ERR_SEEN, count = 0;
475  }
476  fp->_IO_read_end += count;
477  if (count == 0)
478    return EOF;
479  if (fp->_offset != _IO_pos_BAD)
480    _IO_pos_adjust (fp->_offset, count);
481  return *(unsigned char *) fp->_IO_read_ptr;
482}
483
484int
485_IO_new_file_overflow (f, ch)
486      _IO_FILE *f;
487      int ch;
488{
489  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
490    {
491      f->_flags |= _IO_ERR_SEEN;
492      __set_errno (EBADF);
493      return EOF;
494    }
495  /* If currently reading or no buffer allocated. */
496  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == 0)
497    {
498      /* Allocate a buffer if needed. */
499      if (f->_IO_write_base == 0)
500	{
501	  _IO_doallocbuf (f);
502	  _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
503	}
504      /* Otherwise must be currently reading.
505	 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
506	 logically slide the buffer forwards one block (by setting the
507	 read pointers to all point at the beginning of the block).  This
508	 makes room for subsequent output.
509	 Otherwise, set the read pointers to _IO_read_end (leaving that
510	 alone, so it can continue to correspond to the external position). */
511      if (f->_IO_read_ptr == f->_IO_buf_end)
512	f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
513      f->_IO_write_ptr = f->_IO_read_ptr;
514      f->_IO_write_base = f->_IO_write_ptr;
515      f->_IO_write_end = f->_IO_buf_end;
516      f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
517
518      f->_flags |= _IO_CURRENTLY_PUTTING;
519      if (f->_mode < 0 && f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
520	f->_IO_write_end = f->_IO_write_ptr;
521    }
522  if (ch == EOF)
523    return _IO_new_do_write(f, f->_IO_write_base,
524			    f->_IO_write_ptr - f->_IO_write_base);
525  if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
526    if (_IO_do_flush (f) == EOF)
527      return EOF;
528  *f->_IO_write_ptr++ = ch;
529  if ((f->_flags & _IO_UNBUFFERED)
530      || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
531    if (_IO_new_do_write(f, f->_IO_write_base,
532			 f->_IO_write_ptr - f->_IO_write_base) == EOF)
533      return EOF;
534  return (unsigned char) ch;
535}
536
537int
538_IO_new_file_sync (fp)
539     _IO_FILE *fp;
540{
541  _IO_ssize_t delta;
542  int retval = 0;
543
544  /*    char* ptr = cur_ptr(); */
545  if (fp->_IO_write_ptr > fp->_IO_write_base)
546    if (_IO_do_flush(fp)) return EOF;
547  delta = fp->_IO_read_ptr - fp->_IO_read_end;
548  if (delta != 0)
549    {
550#ifdef TODO
551      if (_IO_in_backup (fp))
552	delta -= eGptr () - Gbase ();
553#endif
554      _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1);
555      if (new_pos != (_IO_off64_t) EOF)
556	fp->_IO_read_end = fp->_IO_read_ptr;
557#ifdef ESPIPE
558      else if (errno == ESPIPE)
559	; /* Ignore error from unseekable devices. */
560#endif
561      else
562	retval = EOF;
563    }
564  if (retval != EOF)
565    fp->_offset = _IO_pos_BAD;
566  /* FIXME: Cleanup - can this be shared? */
567  /*    setg(base(), ptr, ptr); */
568  return retval;
569}
570
571_IO_off64_t
572_IO_new_file_seekoff (fp, offset, dir, mode)
573     _IO_FILE *fp;
574     _IO_off64_t offset;
575     int dir;
576     int mode;
577{
578  _IO_off64_t result;
579  _IO_off64_t delta, new_offset;
580  long count;
581  /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
582     offset of the underlying file must be exact.  */
583  int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
584		       && fp->_IO_write_base == fp->_IO_write_ptr);
585
586  if (mode == 0)
587    dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
588
589  /* Flush unwritten characters.
590     (This may do an unneeded write if we seek within the buffer.
591     But to be able to switch to reading, we would need to set
592     egptr to ptr.  That can't be done in the current design,
593     which assumes file_ptr() is eGptr.  Anyway, since we probably
594     end up flushing when we close(), it doesn't make much difference.)
595     FIXME: simulate mem-papped files. */
596
597  if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
598    if (_IO_switch_to_get_mode (fp))
599      return EOF;
600
601  if (fp->_IO_buf_base == NULL)
602    {
603      /* It could be that we already have a pushback buffer.  */
604      if (fp->_IO_read_base != NULL)
605	{
606	  free (fp->_IO_read_base);
607	  fp->_flags &= ~_IO_IN_BACKUP;
608	}
609      _IO_doallocbuf (fp);
610      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
611      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
612    }
613
614  switch (dir)
615    {
616    case _IO_seek_cur:
617      /* Adjust for read-ahead (bytes is buffer). */
618      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
619      if (fp->_offset == _IO_pos_BAD)
620	goto dumb;
621      /* Make offset absolute, assuming current pointer is file_ptr(). */
622      offset += fp->_offset;
623
624      dir = _IO_seek_set;
625      break;
626    case _IO_seek_set:
627      break;
628    case _IO_seek_end:
629      {
630	struct _G_stat64 st;
631	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
632	  {
633	    offset += st.st_size;
634	    dir = _IO_seek_set;
635	  }
636	else
637	  goto dumb;
638      }
639    }
640  /* At this point, dir==_IO_seek_set. */
641
642  /* If we are only interested in the current position we've found it now.  */
643  if (mode == 0)
644    return offset;
645
646  /* If destination is within current buffer, optimize: */
647  if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
648      && !_IO_in_backup (fp))
649    {
650      /* Offset relative to start of main get area. */
651      _IO_off64_t rel_offset = (offset - fp->_offset
652				+ (fp->_IO_read_end - fp->_IO_read_base));
653      if (rel_offset >= 0)
654	{
655#if 0
656	  if (_IO_in_backup (fp))
657	    _IO_switch_to_main_get_area (fp);
658#endif
659	  if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
660	    {
661	      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
662			fp->_IO_read_end);
663	      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
664	      {
665		_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
666		goto resync;
667	      }
668	    }
669#ifdef TODO
670	    /* If we have streammarkers, seek forward by reading ahead. */
671	    if (_IO_have_markers (fp))
672	      {
673		int to_skip = rel_offset
674		  - (fp->_IO_read_ptr - fp->_IO_read_base);
675		if (ignore (to_skip) != to_skip)
676		  goto dumb;
677		_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
678		goto resync;
679	      }
680#endif
681	}
682#ifdef TODO
683      if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
684	{
685	  if (!_IO_in_backup (fp))
686	    _IO_switch_to_backup_area (fp);
687	  gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
688	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
689	  goto resync;
690	}
691#endif
692    }
693
694#ifdef TODO
695  _IO_unsave_markers (fp);
696#endif
697
698  if (fp->_flags & _IO_NO_READS)
699    goto dumb;
700
701  /* Try to seek to a block boundary, to improve kernel page management. */
702  new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
703  delta = offset - new_offset;
704  if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
705    {
706      new_offset = offset;
707      delta = 0;
708    }
709  result = _IO_SYSSEEK (fp, new_offset, 0);
710  if (result < 0)
711    return EOF;
712  if (delta == 0)
713    count = 0;
714  else
715    {
716      count = _IO_SYSREAD (fp, fp->_IO_buf_base,
717			   (must_be_exact
718			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
719      if (count < delta)
720	{
721	  /* We weren't allowed to read, but try to seek the remainder. */
722	  offset = count == EOF ? delta : delta-count;
723	  dir = _IO_seek_cur;
724	  goto dumb;
725	}
726    }
727  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
728	    fp->_IO_buf_base + count);
729  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
730  fp->_offset = result + count;
731  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
732  return offset;
733 dumb:
734
735  _IO_unsave_markers (fp);
736  result = _IO_SYSSEEK (fp, offset, dir);
737  if (result != EOF)
738    {
739      _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
740      fp->_offset = result;
741      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
742      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
743    }
744  return result;
745
746resync:
747  /* We need to do it since it is possible that the file offset in
748     the kernel may be changed behind our back. It may happen when
749     we fopen a file and then do a fork. One process may access the
750     the file and the kernel file offset will be changed. */
751  if (fp->_offset >= 0)
752    _IO_SYSSEEK (fp, fp->_offset, 0);
753
754  return offset;
755}
756
757_IO_ssize_t
758_IO_file_read (fp, buf, size)
759     _IO_FILE *fp;
760     void *buf;
761     _IO_ssize_t size;
762{
763  return read (fp->_fileno, buf, size);
764}
765
766_IO_off64_t
767_IO_file_seek (fp, offset, dir)
768     _IO_FILE *fp;
769     _IO_off64_t offset;
770     int dir;
771{
772#ifdef _G_LSEEK64
773  return _G_LSEEK64 (fp->_fileno, offset, dir);
774#else
775  return lseek (fp->_fileno, offset, dir);
776#endif
777}
778
779int
780_IO_file_stat (fp, st)
781     _IO_FILE *fp;
782     void *st;
783{
784#ifdef _G_FSTAT64
785  return _G_FSTAT64 (fp->_fileno, (struct _G_stat64 *) st);
786#else
787  return fstat (fp->_fileno, (struct stat *) st);
788#endif
789}
790
791int
792_IO_file_close (fp)
793     _IO_FILE *fp;
794{
795  return close (fp->_fileno);
796}
797
798_IO_ssize_t
799_IO_new_file_write (f, data, n)
800     _IO_FILE *f;
801     const void *data;
802     _IO_ssize_t n;
803{
804  _IO_ssize_t to_do = n;
805  while (to_do > 0)
806    {
807      _IO_ssize_t count = write (f->_fileno, data, to_do);
808      if (count < 0)
809	{
810	  f->_flags |= _IO_ERR_SEEN;
811	  break;
812        }
813      to_do -= count;
814      data = (void *) ((char *) data + count);
815    }
816  n -= to_do;
817  if (f->_offset >= 0)
818    f->_offset += n;
819  return n;
820}
821
822_IO_size_t
823_IO_new_file_xsputn (f, data, n)
824     _IO_FILE *f;
825     const void *data;
826     _IO_size_t n;
827{
828  register const char *s = (const char *) data;
829  _IO_size_t to_do = n;
830  int must_flush = 0;
831  _IO_size_t count;
832
833  if (n <= 0)
834    return 0;
835  /* This is an optimized implementation.
836     If the amount to be written straddles a block boundary
837     (or the filebuf is unbuffered), use sys_write directly. */
838
839  /* First figure out how much space is available in the buffer. */
840  count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
841  if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
842    {
843      count = f->_IO_buf_end - f->_IO_write_ptr;
844      if (count >= n)
845	{
846	  register const char *p;
847	  for (p = s + n; p > s; )
848	    {
849	      if (*--p == '\n')
850		{
851		  count = p - s + 1;
852		  must_flush = 1;
853		  break;
854		}
855	    }
856	}
857    }
858  /* Then fill the buffer. */
859  if (count > 0)
860    {
861      if (count > to_do)
862	count = to_do;
863      if (count > 20)
864	{
865#ifdef _LIBC
866	  f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
867#else
868	  memcpy (f->_IO_write_ptr, s, count);
869	  f->_IO_write_ptr += count;
870#endif
871	  s += count;
872	}
873      else
874	{
875	  register char *p = f->_IO_write_ptr;
876	  register int i = (int) count;
877	  while (--i >= 0)
878	    *p++ = *s++;
879	  f->_IO_write_ptr = p;
880	}
881      to_do -= count;
882    }
883  if (to_do + must_flush > 0)
884    {
885      _IO_size_t block_size, do_write;
886      /* Next flush the (full) buffer. */
887      if (_IO_OVERFLOW (f, EOF) == EOF)
888	return n - to_do;
889
890      /* Try to maintain alignment: write a whole number of blocks.
891	 dont_write is what gets left over. */
892      block_size = f->_IO_buf_end - f->_IO_buf_base;
893      do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
894
895      if (do_write)
896        {
897	  count = new_do_write (f, s, do_write);
898	  to_do -= count;
899	  if (count < do_write)
900	    return n - to_do;
901        }
902
903      /* Now write out the remainder.  Normally, this will fit in the
904	 buffer, but it's somewhat messier for line-buffered files,
905	 so we let _IO_default_xsputn handle the general case. */
906      if (to_do)
907	to_do -= _IO_default_xsputn (f, s+do_write, to_do);
908    }
909  return n - to_do;
910}
911
912_IO_size_t
913_IO_file_xsgetn (fp, data, n)
914     _IO_FILE *fp;
915     void *data;
916     _IO_size_t n;
917{
918  register _IO_size_t want, have;
919  register _IO_ssize_t count;
920  register char *s = data;
921
922  want = n;
923
924  if (fp->_IO_buf_base == NULL)
925    {
926      /* Maybe we already have a push back pointer.  */
927      if (fp->_IO_save_base != NULL)
928	{
929	  free (fp->_IO_save_base);
930	  fp->_flags &= ~_IO_IN_BACKUP;
931	}
932      _IO_doallocbuf (fp);
933    }
934
935  while (want > 0)
936    {
937      have = fp->_IO_read_end - fp->_IO_read_ptr;
938      if (want <= have)
939	{
940	  memcpy (s, fp->_IO_read_ptr, want);
941	  fp->_IO_read_ptr += want;
942	  want = 0;
943	}
944      else
945	{
946	  if (have > 0)
947	    {
948#ifdef _LIBC
949	      s = __mempcpy (s, fp->_IO_read_ptr, have);
950#else
951	      memcpy (s, fp->_IO_read_ptr, have);
952	      s += have;
953#endif
954	      want -= have;
955	      fp->_IO_read_ptr += have;
956	    }
957
958	  /* Check for backup and repeat */
959	  if (_IO_in_backup (fp))
960	    {
961	      _IO_switch_to_main_get_area (fp);
962	      continue;
963	    }
964
965	  /* If we now want less than a buffer, underflow and repeat
966	     the copy.  Otherwise, _IO_SYSREAD directly to
967	     the user buffer. */
968	  if (fp->_IO_buf_base && want < fp->_IO_buf_end - fp->_IO_buf_base)
969	    {
970	      if (__underflow (fp) == EOF)
971		break;
972
973	      continue;
974	    }
975
976	  /* These must be set before the sysread as we might longjmp out
977	     waiting for input. */
978	  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
979	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
980
981	  /* Try to maintain alignment: read a whole number of blocks.  */
982	  count = want;
983	  if (fp->_IO_buf_base)
984	    {
985	      _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
986	      if (block_size >= 128)
987		count -= want % block_size;
988	    }
989
990	  count = _IO_SYSREAD (fp, s, count);
991	  if (count <= 0)
992	    {
993	      if (count == 0)
994		fp->_flags |= _IO_EOF_SEEN;
995	      else
996		fp->_flags |= _IO_ERR_SEEN;
997
998	      break;
999	    }
1000
1001	  s += count;
1002	  want -= count;
1003	  if (fp->_offset != _IO_pos_BAD)
1004	    _IO_pos_adjust (fp->_offset, count);
1005	}
1006    }
1007
1008  return n - want;
1009}
1010
1011struct _IO_jump_t _IO_file_jumps =
1012{
1013  JUMP_INIT_DUMMY,
1014  JUMP_INIT(finish, _IO_new_file_finish),
1015  JUMP_INIT(overflow, _IO_new_file_overflow),
1016  JUMP_INIT(underflow, _IO_new_file_underflow),
1017  JUMP_INIT(uflow, _IO_default_uflow),
1018  JUMP_INIT(pbackfail, _IO_default_pbackfail),
1019  JUMP_INIT(xsputn, _IO_new_file_xsputn),
1020  JUMP_INIT(xsgetn, _IO_file_xsgetn),
1021  JUMP_INIT(seekoff, _IO_new_file_seekoff),
1022  JUMP_INIT(seekpos, _IO_default_seekpos),
1023  JUMP_INIT(setbuf, _IO_new_file_setbuf),
1024  JUMP_INIT(sync, _IO_new_file_sync),
1025  JUMP_INIT(doallocate, _IO_file_doallocate),
1026  JUMP_INIT(read, _IO_file_read),
1027  JUMP_INIT(write, _IO_new_file_write),
1028  JUMP_INIT(seek, _IO_file_seek),
1029  JUMP_INIT(close, _IO_file_close),
1030  JUMP_INIT(stat, _IO_file_stat),
1031  JUMP_INIT(showmanyc, _IO_default_showmanyc),
1032  JUMP_INIT(imbue, _IO_default_imbue)
1033};
1034
1035#ifdef _LIBC
1036versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1);
1037versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1);
1038versioned_symbol (libc, _IO_new_file_close_it, _IO_file_close_it, GLIBC_2_1);
1039versioned_symbol (libc, _IO_new_file_finish, _IO_file_finish, GLIBC_2_1);
1040versioned_symbol (libc, _IO_new_file_fopen, _IO_file_fopen, GLIBC_2_1);
1041versioned_symbol (libc, _IO_new_file_init, _IO_file_init, GLIBC_2_1);
1042versioned_symbol (libc, _IO_new_file_setbuf, _IO_file_setbuf, GLIBC_2_1);
1043versioned_symbol (libc, _IO_new_file_sync, _IO_file_sync, GLIBC_2_1);
1044versioned_symbol (libc, _IO_new_file_overflow, _IO_file_overflow, GLIBC_2_1);
1045versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
1046versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
1047versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
1048versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
1049#endif
1050