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