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