1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 
24 /*	Close a stream. A file stream is synced before closing.
25 **
26 **	Written by Kiem-Phong Vo
27 */
28 
29 #if __STD_C
sfclose(Sfio_t * f)30 int sfclose(Sfio_t* f)
31 #else
32 int sfclose(f)
33 Sfio_t*	f;
34 #endif
35 {
36 	reg int		local, ex, rv;
37 	Void_t*		data = NIL(Void_t*);
38 	SFMTXDECL(f); /* declare a local stream variable for multithreading */
39 
40 	SFMTXENTER(f, -1);
41 
42 	GETLOCAL(f,local);
43 
44 	if(!(f->mode&SF_INIT) &&
45 	   SFMODE(f,local) != (f->mode&SF_RDWR) &&
46 	   SFMODE(f,local) != (f->mode&(SF_READ|SF_SYNCED)) &&
47 	   _sfmode(f,SF_SYNCED,local) < 0)
48 		SFMTXRETURN(f,-1);
49 
50 	/* closing a stack of streams */
51 	while(f->push)
52 	{	reg Sfio_t*	pop;
53 
54 		if(!(pop = (*_Sfstack)(f,NIL(Sfio_t*))) )
55 			SFMTXRETURN(f,-1);
56 
57 		if(sfclose(pop) < 0)
58 		{	(*_Sfstack)(f,pop);
59 			SFMTXRETURN(f,-1);
60 		}
61 	}
62 
63 	rv = 0;
64 	if(f->disc == _Sfudisc)	/* closing the ungetc stream */
65 		f->disc = NIL(Sfdisc_t*);
66 	else if(f->file >= 0)	/* sync file pointer */
67 	{	f->bits |= SF_ENDING;
68 		rv = sfsync(f);
69 	}
70 
71 	SFLOCK(f,0);
72 
73 	/* raise discipline exceptions */
74 	if(f->disc && (ex = SFRAISE(f,local ? SF_NEW : SF_CLOSING,NIL(Void_t*))) != 0)
75 		SFMTXRETURN(f,ex);
76 
77 	if(!local && f->pool)
78 	{	/* remove from pool */
79 		if(f->pool == &_Sfpool)
80 		{	reg int	n;
81 
82 			POOLMTXLOCK(&_Sfpool);
83 			for(n = 0; n < _Sfpool.n_sf; ++n)
84 			{	if(_Sfpool.sf[n] != f)
85 					continue;
86 				/* found it */
87 				_Sfpool.n_sf -= 1;
88 				for(; n < _Sfpool.n_sf; ++n)
89 					_Sfpool.sf[n] = _Sfpool.sf[n+1];
90 				break;
91 			}
92 			POOLMTXUNLOCK(&_Sfpool);
93 		}
94 		else
95 		{	f->mode &= ~SF_LOCK;	/**/ASSERT(_Sfpmove);
96 			if((*_Sfpmove)(f,-1) < 0)
97 			{	SFOPEN(f,0);
98 				SFMTXRETURN(f,-1);
99 			}
100 			f->mode |= SF_LOCK;
101 		}
102 		f->pool = NIL(Sfpool_t*);
103 	}
104 
105 	if(f->data && (!local || (f->flags&SF_STRING) || (f->bits&SF_MMAP) ) )
106 	{	/* free buffer */
107 #ifdef MAP_TYPE
108 		if(f->bits&SF_MMAP)
109 			SFMUNMAP(f,f->data,f->endb-f->data);
110 		else
111 #endif
112 		if(f->flags&SF_MALLOC)
113 			data = (Void_t*)f->data;
114 
115 		f->data = NIL(uchar*);
116 		f->size = -1;
117 	}
118 
119 	/* zap the file descriptor */
120 	if(_Sfnotify)
121 		(*_Sfnotify)(f, SF_CLOSING, (void*)((long)f->file));
122 	if(f->file >= 0 && !(f->flags&SF_STRING))
123 	{	while(sysclosef(f->file) < 0 )
124 		{	if(errno == EINTR)
125 				errno = 0;
126 			else
127 			{	rv = -1;
128 				break;
129 			}
130 		}
131 	}
132 	f->file = -1;
133 
134 	SFKILL(f);
135 	f->flags &= SF_STATIC;
136 	f->here = 0;
137 	f->extent = -1;
138 	f->endb = f->endr = f->endw = f->next = f->data;
139 
140 	/* zap any associated auxiliary buffer */
141 	if(f->rsrv)
142 	{	free(f->rsrv);
143 		f->rsrv = NIL(Sfrsrv_t*);
144 	}
145 
146 	/* delete any associated sfpopen-data */
147 	if(f->proc)
148 		rv = _sfpclose(f);
149 
150 	/* destroy the mutex */
151 	if(f->mutex)
152 	{	(void)vtmtxclrlock(f->mutex);
153 		if(f != sfstdin && f != sfstdout && f != sfstderr)
154 		{	(void)vtmtxclose(f->mutex);
155 			f->mutex = NIL(Vtmutex_t*);
156 		}
157 	}
158 
159 	if(!local)
160 	{	if(f->disc && (ex = SFRAISE(f,SF_FINAL,NIL(Void_t*))) != 0 )
161 		{	rv = ex;
162 			goto done;
163 		}
164 
165 		if(!(f->flags&SF_STATIC) )
166 			free(f);
167 		else
168 		{	f->disc = NIL(Sfdisc_t*);
169 			f->stdio = NIL(Void_t*);
170 			f->mode = SF_AVAIL;
171 		}
172 	}
173 
174 done:
175 	if(data)
176 		free(data);
177 	return rv;
178 }
179