Fix fflush issues.

* libc/stdio/fflush.c (_fflush_r): New function.
(fflush): Fix reentrancy and large offset behavior.
* libc/include/stdio.h (_fflush_r): Add prototype.
* libc/stdio/fclose.c (_fclose_r): All fflush callers changed.
* libc/stdio/freopen.c (_freopen_r): Likewise.
* libc/stdio/fseek.c (_fseek_r): Likewise.
* libc/stdio/ftell.c (_ftell_r): Likewise.
* libc/stdio/fvwrite.c (__sfvwrite_r): Likewise.
* libc/stdio/refill.c (__srefill_r): Likewise.
* libc/stdio/setvbuf.c (setvbuf): Likewise.
* libc/stdio/ungetc.c (_ungetc_r): Likewise.
* libc/stdio/vfprintf.c (__sbprintf): Likewise.
* libc/stdio/wbuf.c (__swbuf_r): Likewise.
* libc/stdio64/freopen64.c (_freopen64_r): Likewise.
* libc/stdio64/fseeko64.c (_fseeko64_r): Likewise.  Defer to
32-bit version if not large file.
* libc/stdio64/ftello64.c (_ftello64_r): Likewise.
* libc/stdio64/tmpfile64.c (_tmpfile64_r): Avoid compile warning.
This commit is contained in:
Eric Blake 2007-07-13 20:37:53 +00:00
parent b71fb40215
commit 08146e5adb
17 changed files with 151 additions and 66 deletions

View File

@ -1,5 +1,25 @@
2007-07-13 Eric Blake <ebb9@byu.net> 2007-07-13 Eric Blake <ebb9@byu.net>
Fix fflush issues.
* libc/stdio/fflush.c (_fflush_r): New function.
(fflush): Fix reentrancy and large offset behavior.
* libc/include/stdio.h (_fflush_r): Add prototype.
* libc/stdio/fclose.c (_fclose_r): All fflush callers changed.
* libc/stdio/freopen.c (_freopen_r): Likewise.
* libc/stdio/fseek.c (_fseek_r): Likewise.
* libc/stdio/ftell.c (_ftell_r): Likewise.
* libc/stdio/fvwrite.c (__sfvwrite_r): Likewise.
* libc/stdio/refill.c (__srefill_r): Likewise.
* libc/stdio/setvbuf.c (setvbuf): Likewise.
* libc/stdio/ungetc.c (_ungetc_r): Likewise.
* libc/stdio/vfprintf.c (__sbprintf): Likewise.
* libc/stdio/wbuf.c (__swbuf_r): Likewise.
* libc/stdio64/freopen64.c (_freopen64_r): Likewise.
* libc/stdio64/fseeko64.c (_fseeko64_r): Likewise. Defer to
32-bit version if not large file.
* libc/stdio64/ftello64.c (_ftello64_r): Likewise.
* libc/stdio64/tmpfile64.c (_tmpfile64_r): Avoid compile warning.
Documentation updates. Documentation updates.
* libc/stdio/ungetc.c: Document ungetc. * libc/stdio/ungetc.c: Document ungetc.
* libc/stdio/Makefile.am (CHEWOUT_FILES): Sort, match current list * libc/stdio/Makefile.am (CHEWOUT_FILES): Sort, match current list

View File

@ -348,12 +348,13 @@ int _EXFUN(_dprintf_r, (struct _reent *, int, const char *, ...)
int _EXFUN(_fclose_r, (struct _reent *, FILE *)); int _EXFUN(_fclose_r, (struct _reent *, FILE *));
int _EXFUN(_fcloseall_r, (struct _reent *)); int _EXFUN(_fcloseall_r, (struct _reent *));
FILE * _EXFUN(_fdopen_r, (struct _reent *, int, const char *)); FILE * _EXFUN(_fdopen_r, (struct _reent *, int, const char *));
FILE * _EXFUN(_fopen_r, (struct _reent *, const char *, const char *)); int _EXFUN(_fflush_r, (struct _reent *, FILE *));
char * _EXFUN(_fgets_r, (struct _reent *, char *, int, FILE *)); char * _EXFUN(_fgets_r, (struct _reent *, char *, int, FILE *));
int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...) int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4)))); _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...) int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); _ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
FILE * _EXFUN(_fopen_r, (struct _reent *, const char *, const char *));
int _EXFUN(_fprintf_r, (struct _reent *, FILE *, const char *, ...) int _EXFUN(_fprintf_r, (struct _reent *, FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4)))); _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_fputc_r, (struct _reent *, int, FILE *)); int _EXFUN(_fputc_r, (struct _reent *, int, FILE *));

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1990, 2007 The Regents of the University of California. * Copyright (c) 1990 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms are permitted * Redistribution and use in source and binary forms are permitted
@ -89,7 +89,7 @@ _DEFUN(_fclose_r, (rptr, fp),
/* Unconditionally flush to allow special handling for seekable read /* Unconditionally flush to allow special handling for seekable read
files to reposition file to last byte processed as opposed to files to reposition file to last byte processed as opposed to
last byte read ahead into the buffer. */ last byte read ahead into the buffer. */
r = fflush (fp); r = _fflush_r (rptr, fp);
if (fp->_close != NULL && fp->_close (rptr, fp->_cookie) < 0) if (fp->_close != NULL && fp->_close (rptr, fp->_cookie) < 0)
r = EOF; r = EOF;
if (fp->_flags & __SMBF) if (fp->_flags & __SMBF)

View File

@ -26,10 +26,7 @@ ANSI_SYNOPSIS
#include <stdio.h> #include <stdio.h>
int fflush(FILE *<[fp]>); int fflush(FILE *<[fp]>);
TRAD_SYNOPSIS int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>);
#include <stdio.h>
int fflush(<[fp]>)
FILE *<[fp]>;
DESCRIPTION DESCRIPTION
The <<stdio>> output functions can buffer output before delivering it The <<stdio>> output functions can buffer output before delivering it
@ -41,32 +38,41 @@ or stream identified by <[fp]>) to the host system.
If <[fp]> is <<NULL>>, <<fflush>> delivers pending output from all If <[fp]> is <<NULL>>, <<fflush>> delivers pending output from all
open files. open files.
Additionally, if <[fp]> is a seekable input stream visiting a file
descriptor, set the position of the file descriptor to match next
unread byte, useful for obeying POSIX semantics when ending a process
without consuming all input from the stream.
The alternate function <<_fflush_r>> is a reentrant version, where the
extra argument <[reent]> is a pointer to a reentrancy structure, and
<[fp]> must not be NULL.
RETURNS RETURNS
<<fflush>> returns <<0>> unless it encounters a write error; in that <<fflush>> returns <<0>> unless it encounters a write error; in that
situation, it returns <<EOF>>. situation, it returns <<EOF>>.
PORTABILITY PORTABILITY
ANSI C requires <<fflush>>. ANSI C requires <<fflush>>. The behavior on input streams is only
specified by POSIX, and not all implementations follow POSIX rules.
No supporting OS subroutines are required. No supporting OS subroutines are required.
*/ */
#include <_ansi.h> #include <_ansi.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include "local.h" #include "local.h"
/* Flush a single file, or (if fp is NULL) all files. */ /* Flush a single file, or (if fp is NULL) all files. */
int int
_DEFUN(fflush, (fp), _DEFUN(_fflush_r, (ptr, fp),
struct _reent *ptr _AND
register FILE * fp) register FILE * fp)
{ {
register unsigned char *p; register unsigned char *p;
register int n, t; register int n, t;
if (fp == NULL)
return _fwalk (_GLOBAL_REENT, fflush);
#ifdef _REENT_SMALL #ifdef _REENT_SMALL
/* For REENT_SMALL platforms, it is possible we are being /* For REENT_SMALL platforms, it is possible we are being
called for the first time on a std stream. This std called for the first time on a std stream. This std
@ -83,15 +89,13 @@ _DEFUN(fflush, (fp),
return 0; return 0;
#endif /* _REENT_SMALL */ #endif /* _REENT_SMALL */
CHECK_INIT (_REENT, fp); CHECK_INIT (ptr, fp);
_flockfile (fp); _flockfile (fp);
t = fp->_flags; t = fp->_flags;
if ((t & __SWR) == 0) if ((t & __SWR) == 0)
{ {
_fpos_t _EXFUN((*seekfn), (struct _reent *, _PTR, _fpos_t, int));
/* For a read stream, an fflush causes the next seek to be /* For a read stream, an fflush causes the next seek to be
unoptimized (i.e. forces a system-level seek). This conforms unoptimized (i.e. forces a system-level seek). This conforms
to the POSIX and SUSv3 standards. */ to the POSIX and SUSv3 standards. */
@ -104,22 +108,38 @@ _DEFUN(fflush, (fp),
this seek to be deferred until necessary, but we choose to do it here this seek to be deferred until necessary, but we choose to do it here
to make the change simpler, more contained, and less likely to make the change simpler, more contained, and less likely
to miss a code scenario. */ to miss a code scenario. */
if ((fp->_r > 0 || fp->_ur > 0) && (seekfn = fp->_seek) != NULL) if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
{ {
_fpos_t curoff; int tmp;
#ifdef __LARGE64_FILES
_fpos64_t curoff;
#else
_fpos_t curoff;
#endif
/* Get the physical position we are at in the file. */ /* Get the physical position we are at in the file. */
if (fp->_flags & __SOFF) if (fp->_flags & __SOFF)
curoff = fp->_offset; curoff = fp->_offset;
else else
{ {
/* We don't know current physical offset, so ask for it. */ /* We don't know current physical offset, so ask for it.
curoff = seekfn (_REENT, fp->_cookie, (_fpos_t) 0, SEEK_CUR); Only ESPIPE is ignorable. */
if (curoff == -1L) #ifdef __LARGE64_FILES
{ if (fp->_flags & __SL64)
_funlockfile (fp); curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR);
return 0; else
} #endif
curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR);
if (curoff == -1L)
{
int result = EOF;
if (ptr->_errno == ESPIPE)
result = 0;
else
fp->_flags |= __SERR;
_funlockfile (fp);
return result;
}
} }
if (fp->_flags & __SRD) if (fp->_flags & __SRD)
{ {
@ -129,17 +149,29 @@ _DEFUN(fflush, (fp),
if (HASUB (fp)) if (HASUB (fp))
curoff -= fp->_ur; curoff -= fp->_ur;
} }
/* Now physically seek to after byte last read. */ /* Now physically seek to after byte last read. */
if (seekfn (_REENT, fp->_cookie, curoff, SEEK_SET) != -1) #ifdef __LARGE64_FILES
{ if (fp->_flags & __SL64)
/* Seek successful. We can clear read buffer now. */ tmp = (fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET) == curoff);
fp->_flags &= ~__SNPT; else
fp->_r = 0; #endif
fp->_p = fp->_bf._base; tmp = (fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET) == curoff);
if (fp->_flags & __SOFF) if (tmp)
fp->_offset = curoff; {
} /* Seek successful. We can clear read buffer now. */
} fp->_flags &= ~__SNPT;
fp->_r = 0;
fp->_p = fp->_bf._base;
if (fp->_flags & __SOFF)
fp->_offset = curoff;
}
else
{
fp->_flags |= __SERR;
_funlockfile (fp);
return EOF;
}
}
_funlockfile (fp); _funlockfile (fp);
return 0; return 0;
} }
@ -161,7 +193,7 @@ _DEFUN(fflush, (fp),
while (n > 0) while (n > 0)
{ {
t = fp->_write (_REENT, fp->_cookie, (char *) p, n); t = fp->_write (ptr, fp->_cookie, (char *) p, n);
if (t <= 0) if (t <= 0)
{ {
fp->_flags |= __SERR; fp->_flags |= __SERR;
@ -174,3 +206,17 @@ _DEFUN(fflush, (fp),
_funlockfile (fp); _funlockfile (fp);
return 0; return 0;
} }
#ifndef _REENT_ONLY
int
_DEFUN(fflush, (fp),
register FILE * fp)
{
if (fp == NULL)
return _fwalk_reent (_GLOBAL_REENT, _fflush_r);
return _fflush_r (_REENT, fp);
}
#endif /* _REENT_ONLY */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1990, 2006, 2007 The Regents of the University of California. * Copyright (c) 1990, 2007 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms are permitted * Redistribution and use in source and binary forms are permitted
@ -124,7 +124,7 @@ _DEFUN(_freopen_r, (ptr, file, mode, fp),
else else
{ {
if (fp->_flags & __SWR) if (fp->_flags & __SWR)
fflush (fp); _fflush_r (ptr, fp);
/* /*
* If close is NULL, closing is a no-op, hence pointless. * If close is NULL, closing is a no-op, hence pointless.
* If file is NULL, the file should not be closed. * If file is NULL, the file should not be closed.

View File

@ -145,7 +145,7 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence),
if (fp->_flags & __SAPP && fp->_flags & __SWR) if (fp->_flags & __SAPP && fp->_flags & __SWR)
{ {
/* So flush the buffer and seek to the end. */ /* So flush the buffer and seek to the end. */
fflush (fp); _fflush_r (ptr, fp);
} }
/* Have to be able to seek. */ /* Have to be able to seek. */
@ -170,7 +170,7 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence),
* we have to first find the current stream offset a la * we have to first find the current stream offset a la
* ftell (see ftell for details). * ftell (see ftell for details).
*/ */
fflush (fp); /* may adjust seek offset on append stream */ _fflush_r (ptr, fp); /* may adjust seek offset on append stream */
if (fp->_flags & __SOFF) if (fp->_flags & __SOFF)
curoff = fp->_offset; curoff = fp->_offset;
else else
@ -356,7 +356,8 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence),
*/ */
dumb: dumb:
if (fflush (fp) || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) if (_fflush_r (ptr, fp)
|| seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR)
{ {
_funlockfile (fp); _funlockfile (fp);
return EOF; return EOF;

View File

@ -120,7 +120,7 @@ _DEFUN(_ftell_r, (ptr, fp),
/* Find offset of underlying I/O object, then /* Find offset of underlying I/O object, then
adjust for buffered bytes. */ adjust for buffered bytes. */
fflush(fp); /* may adjust seek offset on append stream */ _fflush_r (ptr, fp); /* may adjust seek offset on append stream */
if (fp->_flags & __SOFF) if (fp->_flags & __SOFF)
pos = fp->_offset; pos = fp->_offset;
else else

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1990, 2006, 2007 The Regents of the University of California. * Copyright (c) 1990 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms are permitted * Redistribution and use in source and binary forms are permitted
@ -185,7 +185,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
COPY (w); COPY (w);
/* fp->_w -= w; *//* unneeded */ /* fp->_w -= w; *//* unneeded */
fp->_p += w; fp->_p += w;
if (fflush (fp)) if (_fflush_r (ptr, fp))
goto err; goto err;
} }
else if (len >= (w = fp->_bf._size)) else if (len >= (w = fp->_bf._size))
@ -235,7 +235,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
COPY (w); COPY (w);
/* fp->_w -= w; */ /* fp->_w -= w; */
fp->_p += w; fp->_p += w;
if (fflush (fp)) if (_fflush_r (ptr, fp))
goto err; goto err;
} }
else if (s >= (w = fp->_bf._size)) else if (s >= (w = fp->_bf._size))
@ -254,7 +254,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
if ((nldist -= w) == 0) if ((nldist -= w) == 0)
{ {
/* copied the newline: flush and forget */ /* copied the newline: flush and forget */
if (fflush (fp)) if (_fflush_r (ptr, fp))
goto err; goto err;
nlknown = 0; nlknown = 0;
} }

View File

@ -65,7 +65,7 @@ _DEFUN(__srefill_r, (ptr, fp),
/* switch to reading */ /* switch to reading */
if (fp->_flags & __SWR) if (fp->_flags & __SWR)
{ {
if (fflush (fp)) if (_fflush_r (ptr, fp))
return EOF; return EOF;
fp->_flags &= ~__SWR; fp->_flags &= ~__SWR;
fp->_w = 0; fp->_w = 0;

View File

@ -126,7 +126,7 @@ _DEFUN(setvbuf, (fp, buf, mode, size),
* non buffer flags, and clear malloc flag. * non buffer flags, and clear malloc flag.
*/ */
_CAST_VOID fflush (fp); _fflush_r (_REENT, fp);
fp->_r = 0; fp->_r = 0;
fp->_lbfsize = 0; fp->_lbfsize = 0;
if (fp->_flags & __SMBF) if (fp->_flags & __SMBF)

View File

@ -143,7 +143,7 @@ _DEFUN(_ungetc_r, (rptr, c, fp),
} }
if (fp->_flags & __SWR) if (fp->_flags & __SWR)
{ {
if (fflush (fp)) if (_fflush_r (rptr, fp))
{ {
_funlockfile (fp); _funlockfile (fp);
return EOF; return EOF;

View File

@ -212,7 +212,7 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
/* do the work, then copy any error status */ /* do the work, then copy any error status */
ret = _VFPRINTF_R (rptr, &fake, fmt, ap); ret = _VFPRINTF_R (rptr, &fake, fmt, ap);
if (ret >= 0 && fflush(&fake)) if (ret >= 0 && _fflush_r (rptr, &fake))
ret = EOF; ret = EOF;
if (fake._flags & __SERR) if (fake._flags & __SERR)
fp->_flags |= __SERR; fp->_flags |= __SERR;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1990, 2007 The Regents of the University of California. * Copyright (c) 1990 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms are permitted * Redistribution and use in source and binary forms are permitted
@ -74,14 +74,14 @@ _DEFUN(__swbuf_r, (ptr, c, fp),
n = fp->_p - fp->_bf._base; n = fp->_p - fp->_bf._base;
if (n >= fp->_bf._size) if (n >= fp->_bf._size)
{ {
if (fflush (fp)) if (_fflush_r (ptr, fp))
return EOF; return EOF;
n = 0; n = 0;
} }
fp->_w--; fp->_w--;
*fp->_p++ = c; *fp->_p++ = c;
if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n'))
if (fflush (fp)) if (_fflush_r (ptr, fp))
return EOF; return EOF;
return c; return c;
} }

View File

@ -124,7 +124,7 @@ _DEFUN (_freopen64_r, (ptr, file, mode, fp),
else else
{ {
if (fp->_flags & __SWR) if (fp->_flags & __SWR)
fflush (fp); _fflush_r (ptr, fp);
/* /*
* If close is NULL, closing is a no-op, hence pointless. * If close is NULL, closing is a no-op, hence pointless.
* If file is NULL, the file should not be closed. * If file is NULL, the file should not be closed.

View File

@ -111,11 +111,22 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence),
struct stat64 st; struct stat64 st;
int havepos; int havepos;
/* Only do 64-bit seek on large file. */
if (!(fp->_flags & __SL64))
{
if ((_off_t) offset != offset)
{
ptr->_errno = EOVERFLOW;
return EOF;
}
return (_off64_t) _fseeko_r (ptr, fp, offset, whence);
}
/* Make sure stdio is set up. */ /* Make sure stdio is set up. */
CHECK_INIT (ptr, fp); CHECK_INIT (ptr, fp);
_flockfile(fp); _flockfile (fp);
curoff = fp->_offset; curoff = fp->_offset;
@ -125,12 +136,12 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence),
if (fp->_flags & __SAPP && fp->_flags & __SWR) if (fp->_flags & __SAPP && fp->_flags & __SWR)
{ {
/* So flush the buffer and seek to the end. */ /* So flush the buffer and seek to the end. */
fflush (fp); _fflush_r (ptr, fp);
} }
/* Have to be able to seek. */ /* Have to be able to seek. */
if ((seekfn = fp->_seek64) == NULL || !(fp->_flags & __SL64)) if ((seekfn = fp->_seek64) == NULL)
{ {
ptr->_errno = ESPIPE; /* ??? */ ptr->_errno = ESPIPE; /* ??? */
_funlockfile(fp); _funlockfile(fp);
@ -150,7 +161,7 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence),
* we have to first find the current stream offset a la * we have to first find the current stream offset a la
* ftell (see ftell for details). * ftell (see ftell for details).
*/ */
fflush(fp); /* may adjust seek offset on append stream */ _fflush_r (ptr, fp); /* may adjust seek offset on append stream */
if (fp->_flags & __SOFF) if (fp->_flags & __SOFF)
curoff = fp->_offset; curoff = fp->_offset;
else else
@ -323,7 +334,8 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence),
*/ */
dumb: dumb:
if (fflush (fp) || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) if (_fflush_r (ptr, fp)
|| seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR)
{ {
_funlockfile(fp); _funlockfile(fp);
return EOF; return EOF;

View File

@ -91,6 +91,10 @@ _DEFUN (_ftello64_r, (ptr, fp),
{ {
_fpos64_t pos; _fpos64_t pos;
/* Only do 64-bit tell on large file. */
if (!(fp->_flags & __SL64))
return (_off64_t) _ftello_r (ptr, fp);
/* Ensure stdio is set up. */ /* Ensure stdio is set up. */
CHECK_INIT (ptr, fp); CHECK_INIT (ptr, fp);
@ -106,7 +110,7 @@ _DEFUN (_ftello64_r, (ptr, fp),
/* Find offset of underlying I/O object, then /* Find offset of underlying I/O object, then
adjust for buffered bytes. */ adjust for buffered bytes. */
fflush(fp); /* may adjust seek offset on append stream */ _fflush_r (ptr, fp); /* may adjust seek offset on append stream */
if (fp->_flags & __SOFF) if (fp->_flags & __SOFF)
pos = fp->_offset; pos = fp->_offset;
else else

View File

@ -48,6 +48,7 @@ Supporting OS subroutines required: <<close>>, <<fstat>>, <<getpid>>,
*/ */
#include <stdio.h> #include <stdio.h>
#include <reent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>