1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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/*	Synchronize data in buffers with the file system.
25**	If f is nil, all streams are sync-ed
26**
27**	Written by Kiem-Phong Vo.
28*/
29
30#if __STD_C
31static int _sfall(void)
32#else
33static int _sfall()
34#endif
35{
36	reg Sfpool_t	*p, *next;
37	reg Sfio_t*	f;
38	reg int		n, rv;
39	reg int		nsync, count, loop;
40#define MAXLOOP 3
41
42	for(loop = 0; loop < MAXLOOP; ++loop)
43	{	rv = nsync = count = 0;
44		for(p = &_Sfpool; p; p = next)
45		{	/* find the next legitimate pool */
46			for(next = p->next; next; next = next->next)
47				if(next->n_sf > 0)
48					break;
49
50			/* walk the streams for _Sfpool only */
51			for(n = 0; n < ((p == &_Sfpool) ? p->n_sf : 1); ++n)
52			{	count += 1;
53				f = p->sf[n];
54
55				if(f->flags&SF_STRING )
56					goto did_sync;
57				if(SFFROZEN(f))
58					continue;
59				if((f->mode&SF_READ) && (f->mode&SF_SYNCED) )
60					goto did_sync;
61				if((f->mode&SF_READ) && !(f->bits&SF_MMAP) &&
62				   f->next == f->endb)
63					goto did_sync;
64				if((f->mode&SF_WRITE) && !(f->bits&SF_HOLE) &&
65				   f->next == f->data)
66					goto did_sync;
67
68				if(sfsync(f) < 0)
69					rv = -1;
70
71			did_sync:
72				nsync += 1;
73			}
74		}
75
76		if(nsync == count)
77			break;
78	}
79	return rv;
80}
81
82#if __STD_C
83int sfsync(reg Sfio_t* f)
84#else
85int sfsync(f)
86reg Sfio_t*	f;	/* stream to be synchronized */
87#endif
88{
89	int	local, rv, mode, lock;
90	Sfio_t*	origf;
91	SFMTXDECL(f);
92
93	if(!(origf = f) )
94		return _sfall();
95
96	SFMTXENTER(origf,-1);
97
98	GETLOCAL(origf,local);
99
100	if(origf->disc == _Sfudisc)	/* throw away ungetc */
101		(void)sfclose((*_Sfstack)(origf,NIL(Sfio_t*)));
102
103	rv = 0;
104
105	lock = origf->mode&SF_LOCK;
106	if(origf->mode == (SF_SYNCED|SF_READ) ) /* already synced */
107		goto done;
108
109	if((origf->mode&SF_RDWR) != SFMODE(origf,local) && _sfmode(origf,0,local) < 0)
110	{	rv = -1;
111		goto done;
112	}
113
114	for(; f; f = f->push)
115	{
116		if((f->flags&SF_IOCHECK) && f->disc && f->disc->exceptf)
117			(void)(*f->disc->exceptf)(f,SF_SYNC,(Void_t*)((int)1),f->disc);
118
119		SFLOCK(f,local);
120
121		/* pretend that this stream is not on a stack */
122		mode = f->mode&SF_PUSH;
123		f->mode &= ~SF_PUSH;
124
125		/* these streams do not need synchronization */
126		if((f->flags&SF_STRING) || (f->mode&SF_SYNCED))
127			goto next;
128
129		if((f->mode&SF_WRITE) && (f->next > f->data || (f->bits&SF_HOLE)) )
130		{	/* sync the buffer, make sure pool don't move */
131			reg int pool = f->mode&SF_POOL;
132			f->mode &= ~SF_POOL;
133			if(f->next > f->data && (SFWRALL(f), SFFLSBUF(f,-1)) < 0)
134				rv = -1;
135			if(!SFISNULL(f) && (f->bits&SF_HOLE) )
136			{	/* realize a previously created hole of 0's */
137				if(SFSK(f,(Sfoff_t)(-1),SEEK_CUR,f->disc) >= 0)
138					(void)SFWR(f,"",1,f->disc);
139				f->bits &= ~SF_HOLE;
140			}
141			f->mode |= pool;
142		}
143
144		if((f->mode&SF_READ) && f->extent >= 0 &&
145		   ((f->bits&SF_MMAP) || f->next < f->endb) )
146		{	/* make sure the file pointer is at the right place */
147			f->here -= (f->endb-f->next);
148			f->endr = f->endw = f->data;
149			f->mode = SF_READ|SF_SYNCED|lock;
150			(void)SFSK(f,f->here,SEEK_SET,f->disc);
151
152			if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC) &&
153			   !(f->bits&SF_MMAP) )
154			{	f->endb = f->next = f->data;
155				f->mode &= ~SF_SYNCED;
156			}
157		}
158
159	next:
160		f->mode |= mode;
161		SFOPEN(f,local);
162
163		if((f->flags&SF_IOCHECK) && f->disc && f->disc->exceptf)
164			(void)(*f->disc->exceptf)(f,SF_SYNC,(Void_t*)((int)0),f->disc);
165	}
166
167done:
168	if(!local && f && (f->mode&SF_POOL) && f->pool && f != f->pool->sf[0])
169		SFSYNC(f->pool->sf[0]);
170
171	SFMTXRETURN(origf, rv);
172}
173