1/* Copyright (C) 1993, 1995, 1997-2002, 2003 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
30#ifndef _POSIX_SOURCE
31# define _POSIX_SOURCE
32#endif
33#include "libioP.h"
34#include <assert.h>
35#include <fcntl.h>
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <string.h>
40#include <errno.h>
41#include <unistd.h>
42#ifdef __STDC__
43#include <stdlib.h>
44#endif
45
46#ifdef _LIBC
47/*# define open(Name, Flags, Prot) __open (Name, Flags, Prot)
48# define close(FD) __close (FD)
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# define _IO_do_write _IO_new_do_write /* For macro uses.  */
53#else
54# define _IO_new_do_write _IO_do_write
55# define _IO_new_file_attach _IO_file_attach
56# define _IO_new_file_close_it _IO_file_close_it
57# define _IO_new_file_finish _IO_file_finish
58# define _IO_new_file_fopen _IO_file_fopen
59# define _IO_new_file_init _IO_file_init
60# define _IO_new_file_setbuf _IO_file_setbuf
61# define _IO_new_file_sync _IO_file_sync
62# define _IO_new_file_overflow _IO_file_overflow
63# define _IO_new_file_seekoff _IO_file_seekoff
64# define _IO_new_file_underflow _IO_file_underflow
65# define _IO_new_file_write _IO_file_write
66# define _IO_new_file_xsputn _IO_file_xsputn
67#endif
68
69#if 0
70#ifdef _LIBC
71extern struct __gconv_trans_data __libio_translit attribute_hidden;
72#endif
73#endif
74
75/* An fstream can be in at most one of put mode, get mode, or putback mode.
76   Putback mode is a variant of get mode.
77
78   In a filebuf, there is only one current position, instead of two
79   separate get and put pointers.  In get mode, the current position
80   is that of gptr(); in put mode that of pptr().
81
82   The position in the buffer that corresponds to the position
83   in external file system is normally _IO_read_end, except in putback
84   mode, when it is _IO_save_end.
85   If the field _fb._offset is >= 0, it gives the offset in
86   the file as a whole corresponding to eGptr(). (?)
87
88   PUT MODE:
89   If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
90   and _IO_read_base are equal to each other.  These are usually equal
91   to _IO_buf_base, though not necessarily if we have switched from
92   get mode to put mode.  (The reason is to maintain the invariant
93   that _IO_read_end corresponds to the external file position.)
94   _IO_write_base is non-NULL and usually equal to _IO_base_base.
95   We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
96   The un-flushed character are those between _IO_write_base and _IO_write_ptr.
97
98   GET MODE:
99   If a filebuf is in get or putback mode, eback() != egptr().
100   In get mode, the unread characters are between gptr() and egptr().
101   The OS file position corresponds to that of egptr().
102
103   PUTBACK MODE:
104   Putback mode is used to remember "excess" characters that have
105   been sputbackc'd in a separate putback buffer.
106   In putback mode, the get buffer points to the special putback buffer.
107   The unread characters are the characters between gptr() and egptr()
108   in the putback buffer, as well as the area between save_gptr()
109   and save_egptr(), which point into the original reserve buffer.
110   (The pointers save_gptr() and save_egptr() are the values
111   of gptr() and egptr() at the time putback mode was entered.)
112   The OS position corresponds to that of save_egptr().
113
114   LINE BUFFERED OUTPUT:
115   During line buffered output, _IO_write_base==base() && epptr()==base().
116   However, ptr() may be anywhere between base() and ebuf().
117   This forces a call to filebuf::overflow(int C) on every put.
118   If there is more space in the buffer, and C is not a '\n',
119   then C is inserted, and pptr() incremented.
120
121   UNBUFFERED STREAMS:
122   If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
123*/
124
125#define CLOSED_FILEBUF_FLAGS \
126  (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
127
128
129void
130_IO_new_file_init (fp)
131     struct _IO_FILE_plus *fp;
132{
133  /* POSIX.1 allows another file handle to be used to change the position
134     of our file descriptor.  Hence we actually don't know the actual
135     position before we do the first fseek (and until a following fflush). */
136  fp->file._offset = _IO_pos_BAD;
137  fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;
138
139  INTUSE(_IO_link_in) (fp);
140  fp->file._fileno = -1;
141}
142INTDEF2(_IO_new_file_init, _IO_file_init)
143
144int
145_IO_new_file_close_it (fp)
146     _IO_FILE *fp;
147{
148  int write_status, close_status;
149  if (!_IO_file_is_open (fp))
150    return EOF;
151
152  if ((fp->_flags & _IO_NO_WRITES) == 0
153      && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)
154    write_status = _IO_do_flush (fp);
155  else
156    write_status = 0;
157
158  INTUSE(_IO_unsave_markers) (fp);
159
160  close_status = _IO_SYSCLOSE (fp);
161
162  /* Free buffer. */
163  if (fp->_mode <= 0)
164    {
165      INTUSE(_IO_setb) (fp, NULL, NULL, 0);
166      _IO_setg (fp, NULL, NULL, NULL);
167      _IO_setp (fp, NULL, NULL);
168    }
169#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
170  else
171    {
172      if (_IO_have_wbackup (fp))
173	INTUSE(_IO_free_wbackup_area) (fp);
174      INTUSE(_IO_wsetb) (fp, NULL, NULL, 0);
175      _IO_wsetg (fp, NULL, NULL, NULL);
176      _IO_wsetp (fp, NULL, NULL);
177    }
178#endif
179
180  INTUSE(_IO_un_link) ((struct _IO_FILE_plus *) fp);
181  fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
182  fp->_fileno = -1;
183  fp->_offset = _IO_pos_BAD;
184
185  return close_status ? close_status : write_status;
186}
187INTDEF2(_IO_new_file_close_it, _IO_file_close_it)
188
189void
190_IO_new_file_finish (fp, dummy)
191     _IO_FILE *fp;
192     int dummy;
193{
194  if (_IO_file_is_open (fp))
195    {
196      _IO_do_flush (fp);
197      if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
198	_IO_SYSCLOSE (fp);
199    }
200  INTUSE(_IO_default_finish) (fp, 0);
201}
202INTDEF2(_IO_new_file_finish, _IO_file_finish)
203
204#if defined __GNUC__ && __GNUC__ >= 2
205__inline__
206#endif
207_IO_FILE *
208_IO_file_open (fp, filename, posix_mode, prot, read_write, is32not64)
209     _IO_FILE *fp;
210     const char *filename;
211     int posix_mode;
212     int prot;
213     int read_write;
214     int is32not64;
215{
216  int fdesc;
217#ifdef _G_OPEN64
218  fdesc = (is32not64
219	   ? open (filename, posix_mode, prot)
220	   : _G_OPEN64 (filename, posix_mode, prot));
221#else
222  fdesc = open (filename, posix_mode, prot);
223#endif
224  if (fdesc < 0)
225    return NULL;
226  fp->_fileno = fdesc;
227  _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
228  if ((read_write & _IO_IS_APPENDING) && (read_write & _IO_NO_READS))
229    if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
230	== _IO_pos_BAD && errno != ESPIPE)
231      {
232	close (fdesc);
233	return NULL;
234      }
235  INTUSE(_IO_link_in) ((struct _IO_FILE_plus *) fp);
236  return fp;
237}
238libc_hidden_def (_IO_file_open)
239
240
241_IO_FILE *
242_IO_new_file_fopen(_IO_FILE *fp, const char *filename, const char *mode, int is32not64)
243{
244  int oflags = 0, omode;
245  int read_write;
246  int oprot = 0666;
247  int i;
248  _IO_FILE *result;
249#ifdef _LIBC
250//  const char *cs;
251  const char *last_recognized;
252#endif
253
254  if (_IO_file_is_open (fp))
255    return 0;
256  switch (*mode)
257    {
258    case 'r':
259      omode = O_RDONLY;
260      read_write = _IO_NO_WRITES;
261      break;
262    case 'w':
263      omode = O_WRONLY;
264      oflags = O_CREAT|O_TRUNC;
265      read_write = _IO_NO_READS;
266      break;
267    case 'a':
268      omode = O_WRONLY;
269      oflags = O_CREAT|O_APPEND;
270      read_write = _IO_NO_READS|_IO_IS_APPENDING;
271      break;
272    default:
273      __set_errno (EINVAL);
274      return NULL;
275    }
276#ifdef _LIBC
277  last_recognized = mode;
278#endif
279  for (i = 1; i < 5; ++i)
280    {
281      switch (*++mode)
282	{
283	case '\0':
284	  break;
285	case '+':
286	  omode = O_RDWR;
287	  read_write &= _IO_IS_APPENDING;
288#ifdef _LIBC
289	  last_recognized = mode;
290#endif
291	  continue;
292	case 'x':
293	  oflags |= O_EXCL;
294#ifdef _LIBC
295	  last_recognized = mode;
296#endif
297	  continue;
298	case 'b':
299#ifdef _LIBC
300	  last_recognized = mode;
301#endif
302	  continue;
303	case 'm':
304	  fp->_flags2 |= _IO_FLAGS2_MMAP;
305	  continue;
306	default:
307	  /* Ignore.  */
308	  continue;
309	}
310      break;
311    }
312
313  result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
314			  is32not64);
315
316#if 0
317#ifdef _LIBC
318  if (result != NULL)
319    {
320      /* Test whether the mode string specifies the conversion.  */
321      cs = strstr (last_recognized + 1, ",ccs=");
322      if (cs != NULL)
323	{
324	  /* Yep.  Load the appropriate conversions and set the orientation
325	     to wide.  */
326	  struct gconv_fcts fcts;
327	  struct _IO_codecvt *cc;
328	  char *endp = __strchrnul (cs + 5, ',');
329	  char ccs[endp - (cs + 5) + 3];
330
331	  *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
332	  strip (ccs, ccs);
333
334	  if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
335				   ? upstr (ccs, cs + 5) : ccs) != 0)
336	    {
337	      /* Something went wrong, we cannot load the conversion modules.
338		 This means we cannot proceed since the user explicitly asked
339		 for these.  */
340	      (void) INTUSE(_IO_file_close_it) (fp);
341	      __set_errno (EINVAL);
342	      return NULL;
343	    }
344
345	  assert (fcts.towc_nsteps == 1);
346	  assert (fcts.tomb_nsteps == 1);
347
348	  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
349	  fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
350
351	  /* Clear the state.  We start all over again.  */
352	  memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
353	  memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
354
355	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
356
357	  /* The functions are always the same.  */
358	  *cc = __libio_codecvt;
359
360	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
361	  cc->__cd_in.__cd.__steps = fcts.towc;
362
363	  cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
364	  cc->__cd_in.__cd.__data[0].__internal_use = 1;
365	  cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
366	  cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
367
368	  /* XXX For now no transliteration.  */
369	  cc->__cd_in.__cd.__data[0].__trans = NULL;
370
371	  cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
372	  cc->__cd_out.__cd.__steps = fcts.tomb;
373
374	  cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
375	  cc->__cd_out.__cd.__data[0].__internal_use = 1;
376	  cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
377	  cc->__cd_out.__cd.__data[0].__statep =
378	    &result->_wide_data->_IO_state;
379
380	  /* And now the transliteration.  */
381	  cc->__cd_out.__cd.__data[0].__trans = &__libio_translit;
382
383	  /* Set the mode now.  */
384	  result->_mode = 1;
385
386	  /* We don't need the step data structure anymore.  */
387	  __gconv_release_cache (fcts.towc, fcts.towc_nsteps);
388	  __gconv_release_cache (fcts.tomb, fcts.tomb_nsteps);
389	}
390    }
391#endif	/* GNU libc */
392#endif
393
394  return result;
395}
396INTDEF2(_IO_new_file_fopen, _IO_file_fopen)
397
398_IO_FILE *
399_IO_new_file_attach (fp, fd)
400     _IO_FILE *fp;
401     int fd;
402{
403  if (_IO_file_is_open (fp))
404    return NULL;
405  fp->_fileno = fd;
406  fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
407  fp->_flags |= _IO_DELETE_DONT_CLOSE;
408  /* Get the current position of the file. */
409  /* We have to do that since that may be junk. */
410  fp->_offset = _IO_pos_BAD;
411  if (_IO_SEEKOFF (fp, (_IO_off64_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
412      == _IO_pos_BAD && errno != ESPIPE)
413    return NULL;
414  return fp;
415}
416INTDEF2(_IO_new_file_attach, _IO_file_attach)
417
418_IO_FILE *
419_IO_new_file_setbuf (fp, p, len)
420     _IO_FILE *fp;
421     char *p;
422     _IO_ssize_t len;
423{
424  if (_IO_default_setbuf (fp, p, len) == NULL)
425    return NULL;
426
427  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
428    = fp->_IO_buf_base;
429  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
430
431  return fp;
432}
433INTDEF2(_IO_new_file_setbuf, _IO_file_setbuf)
434
435
436_IO_FILE *
437_IO_file_setbuf_mmap(_IO_FILE *fp, char *p, _IO_ssize_t len)
438{
439	_IO_FILE *result;
440
441	/* Change the function table. */
442	_IO_JUMPS((struct _IO_FILE_plus *)fp) = &INTUSE(_IO_file_jumps);
443	fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
444
445	/* And perform the normal operation. */
446	result = _IO_new_file_setbuf(fp, p, len);
447
448#if HAVE_MMAP
449	/* If the call failed, restore to using mmap. */
450	if (result == NULL) {
451		_IO_JUMPS((struct _IO_FILE_plus *)fp) = &_IO_file_jumps_mmap;
452		fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
453	}
454#endif
455
456	return result;
457}
458
459static int new_do_write __P ((_IO_FILE *, const char *, _IO_size_t));
460
461/* Write TO_DO bytes from DATA to FP.
462   Then mark FP as having empty buffers. */
463
464int
465_IO_new_do_write (fp, data, to_do)
466     _IO_FILE *fp;
467     const char *data;
468     _IO_size_t to_do;
469{
470  return (to_do == 0
471	  || (_IO_size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
472}
473INTDEF2(_IO_new_do_write, _IO_do_write)
474
475static
476int
477new_do_write (fp, data, to_do)
478     _IO_FILE *fp;
479     const char *data;
480     _IO_size_t to_do;
481{
482  _IO_size_t count;
483  if (fp->_flags & _IO_IS_APPENDING)
484    /* On a system without a proper O_APPEND implementation,
485       you would need to sys_seek(0, SEEK_END) here, but is
486       is not needed nor desirable for Unix- or Posix-like systems.
487       Instead, just indicate that offset (before and after) is
488       unpredictable. */
489    fp->_offset = _IO_pos_BAD;
490  else if (fp->_IO_read_end != fp->_IO_write_base)
491    {
492      _IO_off64_t new_pos
493	= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
494      if (new_pos == _IO_pos_BAD)
495	return 0;
496      fp->_offset = new_pos;
497    }
498  count = _IO_SYSWRITE (fp, data, to_do);
499  if (fp->_cur_column && count)
500    fp->_cur_column = INTUSE(_IO_adjust_column) (fp->_cur_column - 1, data,
501						 count) + 1;
502  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
503  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
504  fp->_IO_write_end = (fp->_mode <= 0
505		       && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
506		       ? fp->_IO_buf_base : fp->_IO_buf_end);
507  return count;
508}
509
510int
511_IO_new_file_underflow (fp)
512     _IO_FILE *fp;
513{
514  _IO_ssize_t count;
515#if 0
516  /* SysV does not make this test; take it out for compatibility */
517  if (fp->_flags & _IO_EOF_SEEN)
518    return (EOF);
519#endif
520
521  if (fp->_flags & _IO_NO_READS)
522    {
523      fp->_flags |= _IO_ERR_SEEN;
524      __set_errno (EBADF);
525      return EOF;
526    }
527  if (fp->_IO_read_ptr < fp->_IO_read_end)
528    return *(unsigned char *) fp->_IO_read_ptr;
529
530  if (fp->_IO_buf_base == NULL)
531    {
532      /* Maybe we already have a push back pointer.  */
533      if (fp->_IO_save_base != NULL)
534	{
535	  free (fp->_IO_save_base);
536	  fp->_flags &= ~_IO_IN_BACKUP;
537	}
538      INTUSE(_IO_doallocbuf) (fp);
539    }
540
541  /* Flush all line buffered files before reading. */
542  /* FIXME This can/should be moved to genops ?? */
543  if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
544    {
545#if 0
546      INTUSE(_IO_flush_all_linebuffered) ();
547#else
548      /* We used to flush all line-buffered stream.  This really isn't
549	 required by any standard.  My recollection is that
550	 traditional Unix systems did this for stdout.  stderr better
551	 not be line buffered.  So we do just that here
552	 explicitly.  --drepper */
553      _IO_cleanup_region_start ((void (*) __P ((void *))) _IO_funlockfile,
554				_IO_stdout);
555      _IO_flockfile (_IO_stdout);
556
557      if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
558	  == (_IO_LINKED | _IO_LINE_BUF))
559	_IO_OVERFLOW (_IO_stdout, EOF);
560
561      _IO_funlockfile (_IO_stdout);
562      _IO_cleanup_region_end (0);
563#endif
564    }
565
566  INTUSE(_IO_switch_to_get_mode) (fp);
567
568  /* This is very tricky. We have to adjust those
569     pointers before we call _IO_SYSREAD () since
570     we may longjump () out while waiting for
571     input. Those pointers may be screwed up. H.J. */
572  fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
573  fp->_IO_read_end = fp->_IO_buf_base;
574  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
575    = fp->_IO_buf_base;
576
577  count = _IO_SYSREAD (fp, fp->_IO_buf_base,
578		       fp->_IO_buf_end - fp->_IO_buf_base);
579  if (count <= 0)
580    {
581      if (count == 0)
582	fp->_flags |= _IO_EOF_SEEN;
583      else
584	fp->_flags |= _IO_ERR_SEEN, count = 0;
585  }
586  fp->_IO_read_end += count;
587  if (count == 0)
588    return EOF;
589  if (fp->_offset != _IO_pos_BAD)
590    _IO_pos_adjust (fp->_offset, count);
591  return *(unsigned char *) fp->_IO_read_ptr;
592}
593INTDEF2(_IO_new_file_underflow, _IO_file_underflow)
594
595#ifdef HAVE_MMAP
596/* Guts of underflow callback if we mmap the file.  This stats the file and
597   updates the stream state to match.  In the normal case we return zero.
598   If the file is no longer eligible for mmap, its jump tables are reset to
599   the vanilla ones and we return nonzero.  */
600static int
601mmap_remap_check (_IO_FILE *fp)
602{
603  struct _G_stat64 st;
604
605  if (_IO_SYSSTAT (fp, &st) == 0
606      && S_ISREG (st.st_mode) && st.st_size != 0
607      /* Limit the file size to 1MB for 32-bit machines.  */
608      && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024))
609    {
610      const size_t pagesize = __getpagesize ();
611# define ROUNDED(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
612      if (ROUNDED (st.st_size) < ROUNDED (fp->_IO_buf_end
613					  - fp->_IO_buf_base))
614	{
615	  /* We can trim off some pages past the end of the file.  */
616	  (void) __munmap (fp->_IO_buf_base + ROUNDED (st.st_size),
617			   ROUNDED (fp->_IO_buf_end - fp->_IO_buf_base)
618			   - ROUNDED (st.st_size));
619	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
620	}
621      else if (ROUNDED (st.st_size) > ROUNDED (fp->_IO_buf_end
622					       - fp->_IO_buf_base))
623	{
624	  /* The file added some pages.  We need to remap it.  */
625	  void *p;
626#if defined __linux__		/* XXX */
627	  p = __mremap (fp->_IO_buf_base, ROUNDED (fp->_IO_buf_end
628						   - fp->_IO_buf_base),
629			ROUNDED (st.st_size), MREMAP_MAYMOVE);
630	  if (p == MAP_FAILED)
631	    {
632	      (void) __munmap (fp->_IO_buf_base,
633			       fp->_IO_buf_end - fp->_IO_buf_base);
634	      goto punt;
635	    }
636#else
637	  (void) __munmap (fp->_IO_buf_base,
638			   fp->_IO_buf_end - fp->_IO_buf_base);
639# ifdef _G_MMAP64
640	  p = _G_MMAP64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
641			 fp->_fileno, 0);
642# else
643	  p = __mmap (NULL, st.st_size, PROT_READ, MAP_SHARED,
644		      fp->_fileno, 0);
645# endif
646	  if (p == MAP_FAILED)
647	    goto punt;
648#endif
649	  fp->_IO_buf_base = p;
650	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
651	}
652      else
653	{
654	  /* The number of pages didn't change.  */
655	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
656	}
657# undef ROUNDED
658
659      fp->_offset -= fp->_IO_read_end - fp->_IO_read_ptr;
660      _IO_setg (fp, fp->_IO_buf_base,
661		fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base
662		? fp->_IO_buf_base + fp->_offset : fp->_IO_buf_end,
663		fp->_IO_buf_end);
664
665      /* If we are already positioned at or past the end of the file, don't
666	 change the current offset.  If not, seek past what we have mapped,
667	 mimicking the position left by a normal underflow reading into its
668	 buffer until EOF.  */
669
670      if (fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base)
671	{
672	  if (
673# ifdef _G_LSEEK64
674	      _G_LSEEK64
675# else
676	      __lseek
677# endif
678	      (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base, SEEK_SET)
679	      != fp->_IO_buf_end - fp->_IO_buf_base)
680	    fp->_flags |= _IO_ERR_SEEN;
681	  else
682	    fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base;
683	}
684
685      return 0;
686    }
687  else
688    {
689		/* Life is no longer good for mmap.  Punt it.  */
690		__munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
691
692punt:
693		fp->_IO_buf_base = fp->_IO_buf_end = NULL;
694		_IO_setg (fp, NULL, NULL, NULL);
695
696		if (fp->_mode <= 0)
697			_IO_JUMPS((struct _IO_FILE_plus *)fp) = &INTUSE(_IO_file_jumps);
698		else
699			_IO_JUMPS((struct _IO_FILE_plus *)fp) = &_IO_wfile_jumps;
700
701		fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
702
703		return 1;
704	}
705}
706
707
708/* Special callback replacing the underflow callbacks if we mmap the file.  */
709int
710_IO_file_underflow_mmap (_IO_FILE *fp)
711{
712  if (fp->_IO_read_ptr < fp->_IO_read_end)
713    return *(unsigned char *) fp->_IO_read_ptr;
714
715  if (__builtin_expect (mmap_remap_check (fp), 0))
716    /* We punted to the regular file functions.  */
717    return _IO_UNDERFLOW (fp);
718
719  if (fp->_IO_read_ptr < fp->_IO_read_end)
720    return *(unsigned char *) fp->_IO_read_ptr;
721
722  fp->_flags |= _IO_EOF_SEEN;
723  return EOF;
724}
725
726
727static void
728decide_maybe_mmap(_IO_FILE *fp)
729{
730	/* We use the file in read-only mode.  This could mean we can
731	 * mmap the file and use it without any copying.  But not all
732	 * file descriptors are for mmap-able objects and on 32-bit
733	 * machines we don't want to map files which are too large since
734	 * this would require too much virtual memory.
735	 */
736	struct _G_stat64 st;
737
738	if (_IO_SYSSTAT(fp, &st) == 0
739		&& S_ISREG (st.st_mode) && st.st_size != 0
740		/* Limit the file size to 1MB for 32-bit machines.  */
741		&& (sizeof(ptrdiff_t) > 4 || st.st_size < 1*1024*1024)
742		/* Sanity check.  */
743		&& (fp->_offset == _IO_pos_BAD || fp->_offset <= st.st_size))
744	{
745		/* Try to map the file.  */
746		void *p;
747
748# ifdef _G_MMAP64
749		p = _G_MMAP64(NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0);
750# else
751		p = __mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0);
752# endif
753
754		if (p != MAP_FAILED) {
755			/* OK, we managed to map the file.  Set the buffer up and use a
756			 * special jump table with simplified underflow functions which
757			 * never tries to read anything from the file.
758			 */
759
760			if (
761# ifdef _G_LSEEK64
762	      _G_LSEEK64
763# else
764	      __lseek
765# endif
766				(fp->_fileno, st.st_size, SEEK_SET) != st.st_size) {
767				(void) __munmap (p, st.st_size);
768				fp->_offset = _IO_pos_BAD;
769			} else {
770				INTUSE(_IO_setb) (fp, p, (char *) p + st.st_size, 0);
771
772				if (fp->_offset == _IO_pos_BAD)
773					fp->_offset = 0;
774
775				_IO_setg (fp, p, p + fp->_offset, p + st.st_size);
776				fp->_offset = st.st_size;
777
778				if (fp->_mode <= 0)
779					_IO_JUMPS((struct _IO_FILE_plus *)fp) = &_IO_file_jumps_mmap;
780				else
781					_IO_JUMPS((struct _IO_FILE_plus *)fp) = &_IO_wfile_jumps_mmap;
782
783				fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
784
785				return;
786			}
787		}
788	}
789
790	/* We couldn't use mmap, so revert to the vanilla file operations. */
791
792	if (fp->_mode <= 0)
793		_IO_JUMPS((struct _IO_FILE_plus *)fp) = &INTUSE(_IO_file_jumps);
794	else
795		_IO_JUMPS((struct _IO_FILE_plus *)fp) = &_IO_wfile_jumps;
796
797	fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
798}
799
800
801int
802_IO_file_underflow_maybe_mmap (_IO_FILE *fp)
803{
804  /* This is the first read attempt.  Choose mmap or vanilla operations
805     and then punt to the chosen underflow routine.  */
806  decide_maybe_mmap (fp);
807  return _IO_UNDERFLOW (fp);
808}
809#endif	/* HAVE_MMAP */
810
811
812int
813_IO_new_file_overflow (f, ch)
814      _IO_FILE *f;
815      int ch;
816{
817  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
818    {
819      f->_flags |= _IO_ERR_SEEN;
820      __set_errno (EBADF);
821      return EOF;
822    }
823  /* If currently reading or no buffer allocated. */
824  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == 0)
825    {
826      /* Allocate a buffer if needed. */
827      if (f->_IO_write_base == 0)
828	{
829	  INTUSE(_IO_doallocbuf) (f);
830	  _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
831	}
832      /* Otherwise must be currently reading.
833	 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
834	 logically slide the buffer forwards one block (by setting the
835	 read pointers to all point at the beginning of the block).  This
836	 makes room for subsequent output.
837	 Otherwise, set the read pointers to _IO_read_end (leaving that
838	 alone, so it can continue to correspond to the external position). */
839      if (f->_IO_read_ptr == f->_IO_buf_end)
840	f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
841      f->_IO_write_ptr = f->_IO_read_ptr;
842      f->_IO_write_base = f->_IO_write_ptr;
843      f->_IO_write_end = f->_IO_buf_end;
844      f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
845
846      f->_flags |= _IO_CURRENTLY_PUTTING;
847      if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
848	f->_IO_write_end = f->_IO_write_ptr;
849    }
850  if (ch == EOF)
851    return INTUSE(_IO_do_write) (f, f->_IO_write_base,
852				 f->_IO_write_ptr - f->_IO_write_base);
853  if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
854    if (_IO_do_flush (f) == EOF)
855      return EOF;
856  *f->_IO_write_ptr++ = ch;
857  if ((f->_flags & _IO_UNBUFFERED)
858      || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
859    if (INTUSE(_IO_do_write) (f, f->_IO_write_base,
860			      f->_IO_write_ptr - f->_IO_write_base) == EOF)
861      return EOF;
862  return (unsigned char) ch;
863}
864INTDEF2(_IO_new_file_overflow, _IO_file_overflow)
865
866int
867_IO_new_file_sync (fp)
868     _IO_FILE *fp;
869{
870  _IO_ssize_t delta;
871  int retval = 0;
872
873  /*    char* ptr = cur_ptr(); */
874  if (fp->_IO_write_ptr > fp->_IO_write_base)
875    if (_IO_do_flush(fp)) return EOF;
876  delta = fp->_IO_read_ptr - fp->_IO_read_end;
877  if (delta != 0)
878    {
879#ifdef TODO
880      if (_IO_in_backup (fp))
881	delta -= eGptr () - Gbase ();
882#endif
883      _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1);
884      if (new_pos != (_IO_off64_t) EOF)
885	fp->_IO_read_end = fp->_IO_read_ptr;
886#ifdef ESPIPE
887      else if (errno == ESPIPE)
888	; /* Ignore error from unseekable devices. */
889#endif
890      else
891	retval = EOF;
892    }
893  if (retval != EOF)
894    fp->_offset = _IO_pos_BAD;
895  /* FIXME: Cleanup - can this be shared? */
896  /*    setg(base(), ptr, ptr); */
897  return retval;
898}
899INTDEF2(_IO_new_file_sync, _IO_file_sync)
900
901#ifdef HAVE_MMAP
902static int
903_IO_file_sync_mmap (_IO_FILE *fp)
904{
905  if (fp->_IO_read_ptr != fp->_IO_read_end)
906    {
907#ifdef TODO
908      if (_IO_in_backup (fp))
909	delta -= eGptr () - Gbase ();
910#endif
911      if (
912# ifdef _G_LSEEK64
913	  _G_LSEEK64
914# else
915	  __lseek
916# endif
917	  (fp->_fileno, fp->_IO_read_ptr - fp->_IO_buf_base, SEEK_SET)
918	  != fp->_IO_read_ptr - fp->_IO_buf_base)
919	{
920	  fp->_flags |= _IO_ERR_SEEN;
921	  return EOF;
922	}
923    }
924  fp->_offset = fp->_IO_read_ptr - fp->_IO_buf_base;
925  fp->_IO_read_end = fp->_IO_read_ptr = fp->_IO_read_base;
926  return 0;
927}
928#endif	/* HAVE_MMAP */
929
930
931_IO_off64_t
932_IO_new_file_seekoff (fp, offset, dir, mode)
933     _IO_FILE *fp;
934     _IO_off64_t offset;
935     int dir;
936     int mode;
937{
938  _IO_off64_t result;
939  _IO_off64_t delta, new_offset;
940  long count;
941  /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
942     offset of the underlying file must be exact.  */
943  int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
944		       && fp->_IO_write_base == fp->_IO_write_ptr);
945
946  if (mode == 0)
947    dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
948
949  /* Flush unwritten characters.
950     (This may do an unneeded write if we seek within the buffer.
951     But to be able to switch to reading, we would need to set
952     egptr to ptr.  That can't be done in the current design,
953     which assumes file_ptr() is eGptr.  Anyway, since we probably
954     end up flushing when we close(), it doesn't make much difference.)
955     FIXME: simulate mem-papped files. */
956
957  if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
958    if (INTUSE(_IO_switch_to_get_mode) (fp))
959      return EOF;
960
961  if (fp->_IO_buf_base == NULL)
962    {
963      /* It could be that we already have a pushback buffer.  */
964      if (fp->_IO_read_base != NULL)
965	{
966	  free (fp->_IO_read_base);
967	  fp->_flags &= ~_IO_IN_BACKUP;
968	}
969      INTUSE(_IO_doallocbuf) (fp);
970      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
971      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
972    }
973
974  switch (dir)
975    {
976    case _IO_seek_cur:
977      /* Adjust for read-ahead (bytes is buffer). */
978      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
979      if (fp->_offset == _IO_pos_BAD)
980	goto dumb;
981      /* Make offset absolute, assuming current pointer is file_ptr(). */
982      offset += fp->_offset;
983      if (offset < 0)
984	{
985	  __set_errno (EINVAL);
986	  return EOF;
987	}
988
989      dir = _IO_seek_set;
990      break;
991    case _IO_seek_set:
992      break;
993    case _IO_seek_end:
994      {
995	struct _G_stat64 st;
996	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
997	  {
998	    offset += st.st_size;
999	    dir = _IO_seek_set;
1000	  }
1001	else
1002	  goto dumb;
1003      }
1004    }
1005  /* At this point, dir==_IO_seek_set. */
1006
1007  /* If we are only interested in the current position we've found it now.  */
1008  if (mode == 0)
1009    return offset;
1010
1011  /* If destination is within current buffer, optimize: */
1012  if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
1013      && !_IO_in_backup (fp))
1014    {
1015      /* Offset relative to start of main get area. */
1016      _IO_off64_t rel_offset = (offset - fp->_offset
1017				+ (fp->_IO_read_end - fp->_IO_buf_base));
1018      if (rel_offset >= 0)
1019	{
1020#if 0
1021	  if (_IO_in_backup (fp))
1022	    _IO_switch_to_main_get_area (fp);
1023#endif
1024	  if (rel_offset <= fp->_IO_read_end - fp->_IO_buf_base)
1025	    {
1026	      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
1027			fp->_IO_read_end);
1028	      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1029	      {
1030		_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1031		goto resync;
1032	      }
1033	    }
1034#ifdef TODO
1035	    /* If we have streammarkers, seek forward by reading ahead. */
1036	    if (_IO_have_markers (fp))
1037	      {
1038		int to_skip = rel_offset
1039		  - (fp->_IO_read_ptr - fp->_IO_read_base);
1040		if (ignore (to_skip) != to_skip)
1041		  goto dumb;
1042		_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1043		goto resync;
1044	      }
1045#endif
1046	}
1047#ifdef TODO
1048      if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
1049	{
1050	  if (!_IO_in_backup (fp))
1051	    _IO_switch_to_backup_area (fp);
1052	  gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
1053	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1054	  goto resync;
1055	}
1056#endif
1057    }
1058
1059#ifdef TODO
1060  INTUSE(_IO_unsave_markers) (fp);
1061#endif
1062
1063  if (fp->_flags & _IO_NO_READS)
1064    goto dumb;
1065
1066  /* Try to seek to a block boundary, to improve kernel page management. */
1067  new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
1068  delta = offset - new_offset;
1069  if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
1070    {
1071      new_offset = offset;
1072      delta = 0;
1073    }
1074  result = _IO_SYSSEEK (fp, new_offset, 0);
1075  if (result < 0)
1076    return EOF;
1077  if (delta == 0)
1078    count = 0;
1079  else
1080    {
1081      count = _IO_SYSREAD (fp, fp->_IO_buf_base,
1082			   (must_be_exact
1083			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
1084      if (count < delta)
1085	{
1086	  /* We weren't allowed to read, but try to seek the remainder. */
1087	  offset = count == EOF ? delta : delta-count;
1088	  dir = _IO_seek_cur;
1089	  goto dumb;
1090	}
1091    }
1092  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
1093	    fp->_IO_buf_base + count);
1094  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1095  fp->_offset = result + count;
1096  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1097  return offset;
1098 dumb:
1099
1100  INTUSE(_IO_unsave_markers) (fp);
1101  result = _IO_SYSSEEK (fp, offset, dir);
1102  if (result != EOF)
1103    {
1104      _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1105      fp->_offset = result;
1106      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
1107      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1108    }
1109  return result;
1110
1111resync:
1112  /* We need to do it since it is possible that the file offset in
1113     the kernel may be changed behind our back. It may happen when
1114     we fopen a file and then do a fork. One process may access the
1115     the file and the kernel file offset will be changed. */
1116  if (fp->_offset >= 0)
1117    _IO_SYSSEEK (fp, fp->_offset, 0);
1118
1119  return offset;
1120}
1121INTDEF2(_IO_new_file_seekoff, _IO_file_seekoff)
1122
1123_IO_off64_t
1124_IO_file_seekoff_mmap (fp, offset, dir, mode)
1125     _IO_FILE *fp;
1126     _IO_off64_t offset;
1127     int dir;
1128     int mode;
1129{
1130  _IO_off64_t result;
1131
1132  /* If we are only interested in the current position, calculate it and
1133     return right now.  This calculation does the right thing when we are
1134     using a pushback buffer, but in the usual case has the same value as
1135     (fp->_IO_read_ptr - fp->_IO_buf_base).  */
1136  if (mode == 0)
1137    return fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr);
1138
1139  switch (dir)
1140    {
1141    case _IO_seek_cur:
1142      /* Adjust for read-ahead (bytes is buffer). */
1143      offset += fp->_IO_read_ptr - fp->_IO_read_base;
1144      break;
1145    case _IO_seek_set:
1146      break;
1147    case _IO_seek_end:
1148      offset += fp->_IO_buf_end - fp->_IO_buf_base;
1149      break;
1150    }
1151  /* At this point, dir==_IO_seek_set. */
1152
1153  if (offset < 0)
1154    {
1155      /* No negative offsets are valid.  */
1156      __set_errno (EINVAL);
1157      return EOF;
1158    }
1159
1160  result = _IO_SYSSEEK (fp, offset, 0);
1161  if (result < 0)
1162    return EOF;
1163
1164  if (offset > fp->_IO_buf_end - fp->_IO_buf_base)
1165    /* One can fseek arbitrarily past the end of the file
1166       and it is meaningless until one attempts to read.
1167       Leave the buffer pointers in EOF state until underflow.  */
1168    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_end, fp->_IO_buf_end);
1169  else
1170    /* Adjust the read pointers to match the file position,
1171       but so the next read attempt will call underflow.  */
1172    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset,
1173	      fp->_IO_buf_base + offset);
1174
1175  fp->_offset = result;
1176
1177  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
1178
1179  return offset;
1180}
1181
1182#ifdef HAVE_MMAP
1183static _IO_off64_t
1184_IO_file_seekoff_maybe_mmap (_IO_FILE *fp, _IO_off64_t offset, int dir,
1185			     int mode)
1186{
1187  /* We only get here when we haven't tried to read anything yet.
1188     So there is nothing more useful for us to do here than just
1189     the underlying lseek call.  */
1190
1191  _IO_off64_t result = _IO_SYSSEEK (fp, offset, dir);
1192  if (result < 0)
1193    return EOF;
1194
1195  fp->_offset = result;
1196  return result;
1197}
1198#endif	/* HAVE_MMAP */
1199
1200_IO_ssize_t
1201_IO_file_read (fp, buf, size)
1202     _IO_FILE *fp;
1203     void *buf;
1204     _IO_ssize_t size;
1205{
1206  return read (fp->_fileno, buf, size);
1207}
1208INTDEF(_IO_file_read)
1209
1210_IO_off64_t
1211_IO_file_seek (fp, offset, dir)
1212     _IO_FILE *fp;
1213     _IO_off64_t offset;
1214     int dir;
1215{
1216#ifdef _G_LSEEK64
1217  return _G_LSEEK64 (fp->_fileno, offset, dir);
1218#else
1219  return lseek (fp->_fileno, offset, dir);
1220#endif
1221}
1222INTDEF(_IO_file_seek)
1223
1224int
1225_IO_file_stat (fp, st)
1226     _IO_FILE *fp;
1227     void *st;
1228{
1229#ifdef _G_FSTAT64
1230  return _G_FSTAT64 (fp->_fileno, (struct _G_stat64 *) st);
1231#else
1232  return fstat (fp->_fileno, (struct stat *) st);
1233#endif
1234}
1235INTDEF(_IO_file_stat)
1236
1237#ifdef HAVE_MMAP
1238int
1239_IO_file_close_mmap (fp)
1240     _IO_FILE *fp;
1241{
1242  /* In addition to closing the file descriptor we have to unmap the file.  */
1243  (void) __munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
1244  fp->_IO_buf_base = fp->_IO_buf_end = NULL;
1245  return close (fp->_fileno);
1246}
1247#endif
1248
1249int
1250_IO_file_close (fp)
1251     _IO_FILE *fp;
1252{
1253  return close (fp->_fileno);
1254}
1255INTDEF(_IO_file_close)
1256
1257_IO_ssize_t
1258_IO_new_file_write (f, data, n)
1259     _IO_FILE *f;
1260     const void *data;
1261     _IO_ssize_t n;
1262{
1263  _IO_ssize_t to_do = n;
1264  while (to_do > 0)
1265    {
1266      _IO_ssize_t count = write (f->_fileno, data, to_do);
1267      if (count < 0)
1268	{
1269	  f->_flags |= _IO_ERR_SEEN;
1270	  break;
1271        }
1272      to_do -= count;
1273      data = (void *) ((char *) data + count);
1274    }
1275  n -= to_do;
1276  if (f->_offset >= 0)
1277    f->_offset += n;
1278  return n;
1279}
1280
1281_IO_size_t
1282_IO_new_file_xsputn (f, data, n)
1283     _IO_FILE *f;
1284     const void *data;
1285     _IO_size_t n;
1286{
1287  register const char *s = (const char *) data;
1288  _IO_size_t to_do = n;
1289  int must_flush = 0;
1290  _IO_size_t count;
1291
1292  if (n <= 0)
1293    return 0;
1294  /* This is an optimized implementation.
1295     If the amount to be written straddles a block boundary
1296     (or the filebuf is unbuffered), use sys_write directly. */
1297
1298  /* First figure out how much space is available in the buffer. */
1299  count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
1300  if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
1301    {
1302      count = f->_IO_buf_end - f->_IO_write_ptr;
1303      if (count >= n)
1304	{
1305	  register const char *p;
1306	  for (p = s + n; p > s; )
1307	    {
1308	      if (*--p == '\n')
1309		{
1310		  count = p - s + 1;
1311		  must_flush = 1;
1312		  break;
1313		}
1314	    }
1315	}
1316    }
1317  /* Then fill the buffer. */
1318  if (count > 0)
1319    {
1320      if (count > to_do)
1321	count = to_do;
1322      if (count > 20)
1323	{
1324#ifdef _LIBC
1325	  f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
1326#else
1327	  memcpy (f->_IO_write_ptr, s, count);
1328	  f->_IO_write_ptr += count;
1329#endif
1330	  s += count;
1331	}
1332      else
1333	{
1334	  register char *p = f->_IO_write_ptr;
1335	  register int i = (int) count;
1336	  while (--i >= 0)
1337	    *p++ = *s++;
1338	  f->_IO_write_ptr = p;
1339	}
1340      to_do -= count;
1341    }
1342  if (to_do + must_flush > 0)
1343    {
1344      _IO_size_t block_size, do_write;
1345      /* Next flush the (full) buffer. */
1346      if (_IO_OVERFLOW (f, EOF) == EOF)
1347	return n - to_do;
1348
1349      /* Try to maintain alignment: write a whole number of blocks.
1350	 dont_write is what gets left over. */
1351      block_size = f->_IO_buf_end - f->_IO_buf_base;
1352      do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
1353
1354      if (do_write)
1355        {
1356	  count = new_do_write (f, s, do_write);
1357	  to_do -= count;
1358	  if (count < do_write)
1359	    return n - to_do;
1360        }
1361
1362      /* Now write out the remainder.  Normally, this will fit in the
1363	 buffer, but it's somewhat messier for line-buffered files,
1364	 so we let _IO_default_xsputn handle the general case. */
1365      if (to_do)
1366	to_do -= INTUSE(_IO_default_xsputn) (f, s+do_write, to_do);
1367    }
1368  return n - to_do;
1369}
1370INTDEF2(_IO_new_file_xsputn, _IO_file_xsputn)
1371
1372_IO_size_t
1373_IO_file_xsgetn (fp, data, n)
1374     _IO_FILE *fp;
1375     void *data;
1376     _IO_size_t n;
1377{
1378  register _IO_size_t want, have;
1379  register _IO_ssize_t count;
1380  register char *s = data;
1381
1382  want = n;
1383
1384  if (fp->_IO_buf_base == NULL)
1385    {
1386      /* Maybe we already have a push back pointer.  */
1387      if (fp->_IO_save_base != NULL)
1388	{
1389	  free (fp->_IO_save_base);
1390	  fp->_flags &= ~_IO_IN_BACKUP;
1391	}
1392      INTUSE(_IO_doallocbuf) (fp);
1393    }
1394
1395  while (want > 0)
1396    {
1397      have = fp->_IO_read_end - fp->_IO_read_ptr;
1398      if (want <= have)
1399	{
1400	  memcpy (s, fp->_IO_read_ptr, want);
1401	  fp->_IO_read_ptr += want;
1402	  want = 0;
1403	}
1404      else
1405	{
1406	  if (have > 0)
1407	    {
1408#ifdef _LIBC
1409	      s = __mempcpy (s, fp->_IO_read_ptr, have);
1410#else
1411	      memcpy (s, fp->_IO_read_ptr, have);
1412	      s += have;
1413#endif
1414	      want -= have;
1415	      fp->_IO_read_ptr += have;
1416	    }
1417
1418	  /* Check for backup and repeat */
1419	  if (_IO_in_backup (fp))
1420	    {
1421	      _IO_switch_to_main_get_area (fp);
1422	      continue;
1423	    }
1424
1425	  /* If we now want less than a buffer, underflow and repeat
1426	     the copy.  Otherwise, _IO_SYSREAD directly to
1427	     the user buffer. */
1428	  if (fp->_IO_buf_base
1429	      && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))
1430	    {
1431	      if (__underflow (fp) == EOF)
1432		break;
1433
1434	      continue;
1435	    }
1436
1437	  /* These must be set before the sysread as we might longjmp out
1438	     waiting for input. */
1439	  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
1440	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1441
1442	  /* Try to maintain alignment: read a whole number of blocks.  */
1443	  count = want;
1444	  if (fp->_IO_buf_base)
1445	    {
1446	      _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
1447	      if (block_size >= 128)
1448		count -= want % block_size;
1449	    }
1450
1451	  count = _IO_SYSREAD (fp, s, count);
1452	  if (count <= 0)
1453	    {
1454	      if (count == 0)
1455		fp->_flags |= _IO_EOF_SEEN;
1456	      else
1457		fp->_flags |= _IO_ERR_SEEN;
1458
1459	      break;
1460	    }
1461
1462	  s += count;
1463	  want -= count;
1464	  if (fp->_offset != _IO_pos_BAD)
1465	    _IO_pos_adjust (fp->_offset, count);
1466	}
1467    }
1468
1469  return n - want;
1470}
1471INTDEF(_IO_file_xsgetn)
1472
1473#ifdef HAVE_MMAP
1474static _IO_size_t _IO_file_xsgetn_mmap __P ((_IO_FILE *, void *, _IO_size_t));
1475static _IO_size_t
1476_IO_file_xsgetn_mmap (fp, data, n)
1477     _IO_FILE *fp;
1478     void *data;
1479     _IO_size_t n;
1480{
1481  register _IO_size_t have;
1482  char *read_ptr = fp->_IO_read_ptr;
1483  register char *s = (char *) data;
1484
1485  have = fp->_IO_read_end - fp->_IO_read_ptr;
1486
1487  if (have < n)
1488    {
1489      if (__builtin_expect (_IO_in_backup (fp), 0))
1490	{
1491#ifdef _LIBC
1492	  s = __mempcpy (s, read_ptr, have);
1493#else
1494	  memcpy (s, read_ptr, have);
1495	  s += have;
1496#endif
1497	  n -= have;
1498	  _IO_switch_to_main_get_area (fp);
1499	  read_ptr = fp->_IO_read_ptr;
1500	  have = fp->_IO_read_end - fp->_IO_read_ptr;
1501	}
1502
1503      if (have < n)
1504	{
1505	  /* Check that we are mapping all of the file, in case it grew.  */
1506	  if (__builtin_expect (mmap_remap_check (fp), 0))
1507	    /* We punted mmap, so complete with the vanilla code.  */
1508	    return s - (char *) data + _IO_XSGETN (fp, data, n);
1509
1510	  read_ptr = fp->_IO_read_ptr;
1511	  have = fp->_IO_read_end - read_ptr;
1512	}
1513    }
1514
1515  if (have < n)
1516    fp->_flags |= _IO_EOF_SEEN;
1517
1518  if (have != 0)
1519    {
1520      have = MIN (have, n);
1521#ifdef _LIBC
1522      s = __mempcpy (s, read_ptr, have);
1523#else
1524      memcpy (s, read_ptr, have);
1525      s += have;
1526#endif
1527      fp->_IO_read_ptr = read_ptr + have;
1528    }
1529
1530  return s - (char *) data;
1531}
1532
1533static _IO_size_t _IO_file_xsgetn_maybe_mmap __P ((_IO_FILE *, void *,
1534						   _IO_size_t));
1535static _IO_size_t
1536_IO_file_xsgetn_maybe_mmap (fp, data, n)
1537     _IO_FILE *fp;
1538     void *data;
1539     _IO_size_t n;
1540{
1541  /* We only get here if this is the first attempt to read something.
1542     Decide which operations to use and then punt to the chosen one.  */
1543
1544  decide_maybe_mmap (fp);
1545  return _IO_XSGETN (fp, data, n);
1546}
1547#endif	/* HAVE_MMAP */
1548
1549#ifdef _LIBC
1550# undef _IO_do_write
1551versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1);
1552versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1);
1553versioned_symbol (libc, _IO_new_file_close_it, _IO_file_close_it, GLIBC_2_1);
1554versioned_symbol (libc, _IO_new_file_finish, _IO_file_finish, GLIBC_2_1);
1555versioned_symbol (libc, _IO_new_file_fopen, _IO_file_fopen, GLIBC_2_1);
1556versioned_symbol (libc, _IO_new_file_init, _IO_file_init, GLIBC_2_1);
1557versioned_symbol (libc, _IO_new_file_setbuf, _IO_file_setbuf, GLIBC_2_1);
1558versioned_symbol (libc, _IO_new_file_sync, _IO_file_sync, GLIBC_2_1);
1559versioned_symbol (libc, _IO_new_file_overflow, _IO_file_overflow, GLIBC_2_1);
1560versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
1561versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
1562versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
1563versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
1564#endif
1565
1566struct _IO_jump_t _IO_file_jumps =
1567{
1568  JUMP_INIT_DUMMY,
1569  JUMP_INIT(finish, INTUSE(_IO_file_finish)),
1570  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
1571  JUMP_INIT(underflow, INTUSE(_IO_file_underflow)),
1572  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
1573  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
1574  JUMP_INIT(xsputn, INTUSE(_IO_file_xsputn)),
1575  JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),
1576  JUMP_INIT(seekoff, _IO_new_file_seekoff),
1577  JUMP_INIT(seekpos, _IO_default_seekpos),
1578  JUMP_INIT(setbuf, _IO_new_file_setbuf),
1579  JUMP_INIT(sync, _IO_new_file_sync),
1580  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
1581  JUMP_INIT(read, INTUSE(_IO_file_read)),
1582  JUMP_INIT(write, _IO_new_file_write),
1583  JUMP_INIT(seek, INTUSE(_IO_file_seek)),
1584  JUMP_INIT(close, INTUSE(_IO_file_close)),
1585  JUMP_INIT(stat, INTUSE(_IO_file_stat)),
1586  JUMP_INIT(showmanyc, _IO_default_showmanyc),
1587  JUMP_INIT(imbue, _IO_default_imbue)
1588};
1589INTVARDEF(_IO_file_jumps)
1590
1591#ifdef HAVE_MMAP
1592struct _IO_jump_t _IO_file_jumps_mmap =
1593{
1594  JUMP_INIT_DUMMY,
1595  JUMP_INIT(finish, INTUSE(_IO_file_finish)),
1596  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
1597  JUMP_INIT(underflow, _IO_file_underflow_mmap),
1598  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
1599  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
1600  JUMP_INIT(xsputn, _IO_new_file_xsputn),
1601  JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
1602  JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
1603  JUMP_INIT(seekpos, _IO_default_seekpos),
1604  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
1605  JUMP_INIT(sync, _IO_file_sync_mmap),
1606  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
1607  JUMP_INIT(read, INTUSE(_IO_file_read)),
1608  JUMP_INIT(write, _IO_new_file_write),
1609  JUMP_INIT(seek, INTUSE(_IO_file_seek)),
1610  JUMP_INIT(close, _IO_file_close_mmap),
1611  JUMP_INIT(stat, INTUSE(_IO_file_stat)),
1612  JUMP_INIT(showmanyc, _IO_default_showmanyc),
1613  JUMP_INIT(imbue, _IO_default_imbue)
1614};
1615
1616struct _IO_jump_t _IO_file_jumps_maybe_mmap =
1617{
1618  JUMP_INIT_DUMMY,
1619  JUMP_INIT(finish, INTUSE(_IO_file_finish)),
1620  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
1621  JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
1622  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
1623  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
1624  JUMP_INIT(xsputn, _IO_new_file_xsputn),
1625  JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
1626  JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
1627  JUMP_INIT(seekpos, _IO_default_seekpos),
1628  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
1629  JUMP_INIT(sync, _IO_new_file_sync),
1630  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
1631  JUMP_INIT(read, INTUSE(_IO_file_read)),
1632  JUMP_INIT(write, _IO_new_file_write),
1633  JUMP_INIT(seek, INTUSE(_IO_file_seek)),
1634  JUMP_INIT(close, _IO_file_close),
1635  JUMP_INIT(stat, INTUSE(_IO_file_stat)),
1636  JUMP_INIT(showmanyc, _IO_default_showmanyc),
1637  JUMP_INIT(imbue, _IO_default_imbue)
1638};
1639#endif	/* HAVE_MMAP */
1640