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 <_ansi.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <sys/lock.h>
56 #include "local.h"
57 
58 int
fclose(register FILE * fp)59 fclose (
60       register FILE * fp)
61 {
62   int r;
63 
64   if (fp == NULL)
65     return (0);			/* on NULL */
66 
67   CHECK_INIT (rptr, fp);
68 
69   /* We can't use the _newlib_flockfile_XXX macros here due to the
70      interlocked locking with the sfp_lock. */
71 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
72   int __oldcancel;
73   pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldcancel);
74 #endif
75   if (!(fp->_flags2 & __SNLK))
76     _flockfile (fp);
77 
78   if (fp->_flags == 0)		/* not open! */
79     {
80       if (!(fp->_flags2 & __SNLK))
81 	_funlockfile (fp);
82 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
83       pthread_setcancelstate (__oldcancel, &__oldcancel);
84 #endif
85       return (0);
86     }
87 #ifdef _STDIO_BSD_SEMANTICS
88   /* BSD and Glibc systems only flush streams which have been written to. */
89   r = (fp->_flags & __SWR) ? _sflush ( fp) : 0;
90 #else
91   /* Follow POSIX semantics exactly.  Unconditionally flush to allow
92      special handling for seekable read files to reposition file to last
93      byte processed as opposed to last byte read ahead into the buffer. */
94   r = _sflush ( fp);
95 #endif
96   if (fp->_close != NULL && fp->_close (fp->_cookie) < 0)
97     r = EOF;
98   if (fp->_flags & __SMBF)
99     free ((char *) fp->_bf._base);
100   if (HASUB (fp))
101     FREEUB (rptr, fp);
102   if (HASLB (fp))
103     FREELB (rptr, fp);
104   __sfp_lock_acquire ();
105   fp->_flags = 0;		/* release this FILE for reuse */
106   if (!(fp->_flags2 & __SNLK))
107     _funlockfile (fp);
108 #ifndef __SINGLE_THREAD__
109   __lock_close_recursive (fp->_lock);
110 #endif
111 
112   __sfp_lock_release ();
113 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
114   pthread_setcancelstate (__oldcancel, &__oldcancel);
115 #endif
116 
117   return (r);
118 }
119