1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * and/or other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 /*
19 FUNCTION
20 <<fclose>>---close a file
21 
22 INDEX
23 	fclose
24 INDEX
25 	_fclose_r
26 
27 SYNOPSIS
28 	#include <stdio.h>
29 	int fclose(FILE *<[fp]>);
30 	int fclose( FILE *<[fp]>);
31 
32 DESCRIPTION
33 If the file or stream identified by <[fp]> is open, <<fclose>> closes
34 it, after first ensuring that any pending data is written (by calling
35 <<fflush(<[fp]>)>>).
36 
37 The alternate function <<_fclose_r>> is a reentrant version.
38 The extra argument <[reent]> is a pointer to a reentrancy structure.
39 
40 RETURNS
41 <<fclose>> returns <<0>> if successful (including when <[fp]> is
42 <<NULL>> or not an open file); otherwise, it returns <<EOF>>.
43 
44 PORTABILITY
45 <<fclose>> is required by ANSI C.
46 
47 Required OS subroutines: <<close>>, <<fstat>>, <<isatty>>, <<lseek>>,
48 <<read>>, <<sbrk>>, <<write>>.
49 */
50 
51 #define _DEFAULT_SOURCE
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <sys/lock.h>
55 #include "local.h"
56 
57 int
fclose(register FILE * fp)58 fclose (
59       register FILE * fp)
60 {
61   int r;
62 
63   if (fp == NULL)
64     return (0);			/* on NULL */
65 
66   CHECK_INIT (rptr, fp);
67 
68   /* We can't use the _newlib_flockfile_XXX macros here due to the
69      interlocked locking with the sfp_lock. */
70 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
71   int __oldcancel;
72   pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldcancel);
73 #endif
74   if (!(fp->_flags2 & __SNLK))
75     _flockfile (fp);
76 
77   if (fp->_flags == 0)		/* not open! */
78     {
79       if (!(fp->_flags2 & __SNLK))
80 	_funlockfile (fp);
81 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
82       pthread_setcancelstate (__oldcancel, &__oldcancel);
83 #endif
84       return (0);
85     }
86 #ifdef _STDIO_BSD_SEMANTICS
87   /* BSD and Glibc systems only flush streams which have been written to. */
88   r = (fp->_flags & __SWR) ? _sflush ( fp) : 0;
89 #else
90   /* Follow POSIX semantics exactly.  Unconditionally flush to allow
91      special handling for seekable read files to reposition file to last
92      byte processed as opposed to last byte read ahead into the buffer. */
93   r = _sflush ( fp);
94 #endif
95   if (fp->_close != NULL && fp->_close (fp->_cookie) < 0)
96     r = EOF;
97   if (fp->_flags & __SMBF)
98     free ((char *) fp->_bf._base);
99   if (HASUB (fp))
100     FREEUB (rptr, fp);
101   if (HASLB (fp))
102     FREELB (rptr, fp);
103   __sfp_lock_acquire ();
104   fp->_flags = 0;		/* release this FILE for reuse */
105   if (!(fp->_flags2 & __SNLK))
106     _funlockfile (fp);
107 #ifndef __SINGLE_THREAD__
108   __lock_close_recursive (fp->_lock);
109 #endif
110 
111   __sfp_lock_release ();
112 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
113   pthread_setcancelstate (__oldcancel, &__oldcancel);
114 #endif
115 
116   return (r);
117 }
118