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
30int sfclose(Sfio_t* f)
31#else
32int sfclose(f)
33Sfio_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
174done:
175	if(data)
176		free(data);
177	return rv;
178}
179