1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
19da2e3ebchin*                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebchin*                                                                      *
21da2e3ebchin***********************************************************************/
22da2e3ebchin#include	"sfhdr.h"
23da2e3ebchin
24da2e3ebchin/*	Move data from one stream to another.
25da2e3ebchin**	This code is written so that it'll work even in the presence
26da2e3ebchin**	of stacking streams, pool, and discipline.
27da2e3ebchin**	If you must change it, be gentle.
28da2e3ebchin**
29da2e3ebchin**	Written by Kiem-Phong Vo.
30da2e3ebchin*/
31da2e3ebchin#define MAX_SSIZE	((ssize_t)((~((size_t)0)) >> 1))
32da2e3ebchin
33da2e3ebchin#if __STD_C
34da2e3ebchinSfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, reg int rc)
35da2e3ebchin#else
36da2e3ebchinSfoff_t sfmove(fr,fw,n,rc)
37da2e3ebchinSfio_t*	fr;	/* moving data from this stream */
38da2e3ebchinSfio_t*	fw;	/* moving data to this stream */
39da2e3ebchinSfoff_t		n;	/* number of bytes/records to move. <0 for unbounded move */
40da2e3ebchinreg int		rc;	/* record separator */
41da2e3ebchin#endif
42da2e3ebchin{
43da2e3ebchin	reg uchar	*cp, *next;
44da2e3ebchin	reg ssize_t	r, w;
45da2e3ebchin	reg uchar	*endb;
46da2e3ebchin	reg int		direct;
47da2e3ebchin	Sfoff_t		n_move, sk, cur;
48da2e3ebchin	uchar		*rbuf = NIL(uchar*);
49da2e3ebchin	ssize_t		rsize = 0;
507c2fbfbApril Chin	SFMTXDECL(fr);
517c2fbfbApril Chin	SFMTXDECL2(fw);
52da2e3ebchin
537c2fbfbApril Chin	SFMTXENTER(fr, (Sfoff_t)0);
54da2e3ebchin	if(fw)
557c2fbfbApril Chin		SFMTXBEGIN2(fw, (Sfoff_t)0);
56da2e3ebchin
57da2e3ebchin	for(n_move = 0; n != 0; )
58da2e3ebchin	{
59da2e3ebchin		if(rc >= 0) /* moving records, let sfgetr() deal with record reading */
60da2e3ebchin		{	if(!(cp = (uchar*)sfgetr(fr,rc,0)) )
61da2e3ebchin				n = 0;
62da2e3ebchin			else
63da2e3ebchin			{	r = sfvalue(fr);
64da2e3ebchin				if(fw && (w = SFWRITE(fw, cp, r)) != r)
65da2e3ebchin				{	if(fr->extent >= 0 )
66da2e3ebchin						(void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
67da2e3ebchin					if(fw->extent >= 0 && w > 0)
68da2e3ebchin						(void)SFSEEK(fw,(Sfoff_t)(-w),SEEK_CUR);
69da2e3ebchin					n = 0;
70da2e3ebchin				}
71da2e3ebchin				else
72da2e3ebchin				{	n_move += 1;
73da2e3ebchin					if(n > 0)
74da2e3ebchin						n -= 1;
75da2e3ebchin				}
76da2e3ebchin			}
77da2e3ebchin			continue;
78da2e3ebchin		}
79da2e3ebchin
80da2e3ebchin		/* get the streams into the right mode */
81da2e3ebchin		if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
82da2e3ebchin			break;
83da2e3ebchin
84da2e3ebchin		SFLOCK(fr,0);
85da2e3ebchin
86da2e3ebchin		/* flush the write buffer as necessary to make room */
87da2e3ebchin		if(fw)
88da2e3ebchin		{	if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 )
89da2e3ebchin				break;
90da2e3ebchin			SFLOCK(fw,0);
91da2e3ebchin			if(fw->next >= fw->endb ||
92da2e3ebchin			   (fw->next > fw->data && fr->extent < 0 &&
93da2e3ebchin			    (fw->extent < 0 || (fw->flags&SF_SHARE)) ) )
94da2e3ebchin				if(SFFLSBUF(fw,-1) < 0 )
95da2e3ebchin					break;
96da2e3ebchin		}
97da2e3ebchin		else if((cur = SFSEEK(fr, (Sfoff_t)0, SEEK_CUR)) >= 0 )
98da2e3ebchin		{	sk = n > 0 ? SFSEEK(fr, n, SEEK_CUR) : SFSEEK(fr, 0, SEEK_END);
99da2e3ebchin			if(sk > cur) /* safe to skip over data in current stream */
100da2e3ebchin			{	n_move += sk - cur;
101da2e3ebchin				if(n > 0)
102da2e3ebchin					n -= sk - cur;
103da2e3ebchin				continue;
104da2e3ebchin			}
105da2e3ebchin			/* else: stream unstacking may happen below */
106da2e3ebchin		}
107da2e3ebchin
108da2e3ebchin		/* about to move all, set map to a large amount */
109da2e3ebchin		if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) )
110da2e3ebchin		{	SFMVSET(fr);
111da2e3ebchin			fr->bits |= SF_SEQUENTIAL; /* sequentially access data */
112da2e3ebchin		}
113da2e3ebchin
114da2e3ebchin		/* try reading a block of data */
115da2e3ebchin		direct = 0;
116da2e3ebchin		if((r = fr->endb - (next = fr->next)) <= 0)
117da2e3ebchin		{	/* amount of data remained to be read */
118da2e3ebchin			if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0)
119da2e3ebchin			{	if(fr->extent < 0)
120da2e3ebchin					w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
121da2e3ebchin				else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
122da2e3ebchin					w = SF_NMAP*SF_PAGE;
123da2e3ebchin				else	w = (ssize_t)(fr->extent-fr->here);
124da2e3ebchin			}
125da2e3ebchin
126da2e3ebchin			/* use a decent buffer for data transfer but make sure
127da2e3ebchin			   that if we overread, the left over can be retrieved
128da2e3ebchin			*/
129da2e3ebchin			if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) &&
130da2e3ebchin			   (n < 0 || fr->extent >= 0) )
131da2e3ebchin			{	reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE);
132da2e3ebchin
133da2e3ebchin				/* direct transfer to a seekable write stream */
134da2e3ebchin				if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) )
135da2e3ebchin				{	w = fw->endb - (next = fw->next);
136da2e3ebchin					direct = SF_WRITE;
137da2e3ebchin				}
138da2e3ebchin				else if(w > fr->size && maxw > fr->size)
139da2e3ebchin				{	/* making our own buffer */
140da2e3ebchin					if(w >= maxw)
141da2e3ebchin						w = maxw;
142da2e3ebchin					else	w = ((w+fr->size-1)/fr->size)*fr->size;
143da2e3ebchin					if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
144da2e3ebchin						rsize = w;
145da2e3ebchin					if(rbuf)
146da2e3ebchin					{	next = rbuf;
147da2e3ebchin						w = rsize;
148da2e3ebchin						direct = SF_STRING;
149da2e3ebchin					}
150da2e3ebchin				}
151da2e3ebchin			}
152da2e3ebchin
153da2e3ebchin			if(!direct)
154da2e3ebchin			{	/* make sure we don't read too far ahead */
155da2e3ebchin				if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) )
156da2e3ebchin				{	if((Sfoff_t)(r = fr->size) > n)
157da2e3ebchin						r = (ssize_t)n;
158da2e3ebchin				}
159da2e3ebchin				else	r = -1;
160da2e3ebchin				if((r = SFFILBUF(fr,r)) <= 0)
161da2e3ebchin					break;
162da2e3ebchin				next = fr->next;
163da2e3ebchin			}
164da2e3ebchin			else
165da2e3ebchin			{	/* actual amount to be read */
166da2e3ebchin				if(n > 0 && n < w)
167da2e3ebchin					w = (ssize_t)n;
168da2e3ebchin
169da2e3ebchin				if((r = SFRD(fr,next,w,fr->disc)) > 0)
170da2e3ebchin					fr->next = fr->endb = fr->endr = fr->data;
171da2e3ebchin				else if(r == 0)
172da2e3ebchin					break;		/* eof */
173da2e3ebchin				else	goto again;	/* popped stack */
174da2e3ebchin			}
175da2e3ebchin		}
176da2e3ebchin
177da2e3ebchin		/* compute the extent of data to be moved */
178da2e3ebchin		endb = next+r;
179da2e3ebchin		if(n > 0)
180da2e3ebchin		{	if(r > n)
181da2e3ebchin				r = (ssize_t)n;
182da2e3ebchin			n -= r;
183da2e3ebchin		}
184da2e3ebchin		n_move += r;
185da2e3ebchin		cp = next+r;
186da2e3ebchin
187da2e3ebchin		if(!direct)
188da2e3ebchin			fr->next += r;
189da2e3ebchin		else if((w = endb-cp) > 0)
190da2e3ebchin		{	/* move left-over to read stream */
191da2e3ebchin			if(w > fr->size)
192da2e3ebchin				w = fr->size;
193da2e3ebchin			memcpy((Void_t*)fr->data,(Void_t*)cp,w);
194da2e3ebchin			fr->endb = fr->data+w;
195da2e3ebchin			if((w = endb - (cp+w)) > 0)
196da2e3ebchin				(void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc);
197da2e3ebchin		}
198da2e3ebchin
199da2e3ebchin		if(fw)
200da2e3ebchin		{	if(direct == SF_WRITE)
201da2e3ebchin				fw->next += r;
202da2e3ebchin			else if(r <= (fw->endb-fw->next) )
203da2e3ebchin			{	memcpy((Void_t*)fw->next,(Void_t*)next,r);
204da2e3ebchin				fw->next += r;
205da2e3ebchin			}
206da2e3ebchin			else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
207da2e3ebchin			{	/* a write error happened */
208da2e3ebchin				if(w > 0)
209da2e3ebchin				{	r -= w;
210da2e3ebchin					n_move -= r;
211da2e3ebchin				}
212da2e3ebchin				if(fr->extent >= 0)
213da2e3ebchin					(void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
214da2e3ebchin				break;
215da2e3ebchin			}
216da2e3ebchin		}
217da2e3ebchin
218da2e3ebchin	again:
219da2e3ebchin		SFOPEN(fr,0);
220da2e3ebchin		if(fw)
221da2e3ebchin			SFOPEN(fw,0);
222da2e3ebchin	}
223da2e3ebchin
224da2e3ebchin	if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE))
225da2e3ebchin	{	/* back to normal access mode */
226da2e3ebchin		SFMVUNSET(fr);
227da2e3ebchin		if((fr->bits&SF_SEQUENTIAL) && (fr->data))
228da2e3ebchin			SFMMSEQOFF(fr,fr->data,fr->endb-fr->data);
229da2e3ebchin		fr->bits &= ~SF_SEQUENTIAL;
230da2e3ebchin	}
231da2e3ebchin
232da2e3ebchin	if(rbuf)
233da2e3ebchin		free(rbuf);
234da2e3ebchin
235da2e3ebchin	if(fw)
236da2e3ebchin	{	SFOPEN(fw,0);
2377c2fbfbApril Chin		SFMTXEND2(fw);
238da2e3ebchin	}
239da2e3ebchin
2407c2fbfbApril Chin	SFOPEN(fr,0);
241da2e3ebchin	SFMTXRETURN(fr, n_move);
242da2e3ebchin}
243