1 /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
2  *
3  * GNU Library General Public License (LGPL) version 2 or later.
4  *
5  * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
6  */
7 
8 #include "_stdio.h"
9 
10 
fclose(register FILE * stream)11 int fclose(register FILE *stream)
12 {
13 	int rv = 0;
14 	__STDIO_AUTO_THREADLOCK_VAR;
15 
16 #ifdef __STDIO_HAS_OPENLIST
17 #if !defined(__UCLIBC_HAS_THREADS__) || !defined(__STDIO_BUFFERS)
18 	/* First, remove the file from the open file list. */
19 	{
20 		FILE *ptr;
21 
22 		__STDIO_THREADLOCK_OPENLIST_DEL;
23 		__STDIO_THREADLOCK_OPENLIST_ADD;
24 		ptr = _stdio_openlist;
25 		if ((ptr = _stdio_openlist) == stream) {
26 			_stdio_openlist = stream->__nextopen;
27 		} else {
28 			while (ptr) {
29 				if (ptr->__nextopen == stream) {
30 					ptr->__nextopen = stream->__nextopen;
31 					break;
32 				}
33 				ptr = ptr->__nextopen;
34 			}
35 		}
36 		__STDIO_THREADUNLOCK_OPENLIST_ADD;
37 		__STDIO_THREADUNLOCK_OPENLIST_DEL;
38 	}
39 #endif
40 #endif
41 
42 	__STDIO_AUTO_THREADLOCK(stream);
43 
44 	__STDIO_STREAM_VALIDATE(stream);
45 
46 #ifdef __STDIO_BUFFERS
47 	/* Write any pending buffered chars. */
48 	if (__STDIO_STREAM_IS_WRITING(stream)) {
49 		rv = fflush_unlocked(stream);
50 	}
51 #endif
52 
53 	if (__CLOSE(stream) < 0) {	/* Must close even if fflush failed. */
54 		rv = EOF;
55 	}
56 
57 	stream->__filedes = -1;
58 
59 	/* We need a way for freopen to know that a file has been closed.
60 	 * Since a file can't be both readonly and writeonly, that makes
61 	 * an effective signal.  It also has the benefit of disabling
62 	 * transitions to either reading or writing. */
63 #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
64 	/* Before we mark the file as closed, make sure we increment the openlist use count
65 	 * so it isn't freed under us while still cleaning up. */
66 	__STDIO_OPENLIST_INC_USE;
67 #endif
68 	stream->__modeflags &= (__FLAG_FREEBUF|__FLAG_FREEFILE);
69 	stream->__modeflags |= (__FLAG_READONLY|__FLAG_WRITEONLY);
70 
71 #ifndef NDEBUG
72 	__STDIO_STREAM_RESET_GCS(stream);
73 
74 	/* Reinitialize everything (including putc since fflush could fail). */
75 	__STDIO_STREAM_DISABLE_GETC(stream);
76 	__STDIO_STREAM_DISABLE_PUTC(stream);
77 	__STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
78 
79 # ifdef __UCLIBC_HAS_WCHAR__
80 	stream->__ungot_width[0] = 0;
81 # endif
82 # ifdef __STDIO_MBSTATE
83 	__INIT_MBSTATE(&(stream->__state));
84 # endif
85 #endif
86 
87 	__STDIO_AUTO_THREADUNLOCK(stream);
88 
89 	__STDIO_STREAM_FREE_BUFFER(stream);
90 #ifdef __UCLIBC_MJN3_ONLY__
91 #warning REMINDER: inefficient - locks and unlocks twice and walks whole list
92 #endif
93 #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
94 	/* inefficient - locks/unlocks twice and walks whole list */
95 	__STDIO_OPENLIST_INC_DEL_CNT;
96 	__STDIO_OPENLIST_DEC_USE;	/* This with free the file if necessary. */
97 #else
98 	__STDIO_STREAM_FREE_FILE(stream);
99 #endif
100 
101 	return rv;
102 }
103 libc_hidden_def(fclose)
104