14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfhdr.h"
234887Schin
244887Schin /* Move data from one stream to another.
254887Schin ** This code is written so that it'll work even in the presence
264887Schin ** of stacking streams, pool, and discipline.
274887Schin ** If you must change it, be gentle.
284887Schin **
294887Schin ** Written by Kiem-Phong Vo.
304887Schin */
314887Schin #define MAX_SSIZE ((ssize_t)((~((size_t)0)) >> 1))
324887Schin
334887Schin #if __STD_C
sfmove(Sfio_t * fr,Sfio_t * fw,Sfoff_t n,reg int rc)344887Schin Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, reg int rc)
354887Schin #else
364887Schin Sfoff_t sfmove(fr,fw,n,rc)
374887Schin Sfio_t* fr; /* moving data from this stream */
384887Schin Sfio_t* fw; /* moving data to this stream */
394887Schin Sfoff_t n; /* number of bytes/records to move. <0 for unbounded move */
404887Schin reg int rc; /* record separator */
414887Schin #endif
424887Schin {
434887Schin reg uchar *cp, *next;
444887Schin reg ssize_t r, w;
454887Schin reg uchar *endb;
464887Schin reg int direct;
474887Schin Sfoff_t n_move, sk, cur;
484887Schin uchar *rbuf = NIL(uchar*);
494887Schin ssize_t rsize = 0;
508462SApril.Chin@Sun.COM SFMTXDECL(fr);
518462SApril.Chin@Sun.COM SFMTXDECL2(fw);
524887Schin
538462SApril.Chin@Sun.COM SFMTXENTER(fr, (Sfoff_t)0);
544887Schin if(fw)
558462SApril.Chin@Sun.COM SFMTXBEGIN2(fw, (Sfoff_t)0);
564887Schin
574887Schin for(n_move = 0; n != 0; )
584887Schin {
594887Schin if(rc >= 0) /* moving records, let sfgetr() deal with record reading */
604887Schin { if(!(cp = (uchar*)sfgetr(fr,rc,0)) )
614887Schin n = 0;
624887Schin else
634887Schin { r = sfvalue(fr);
644887Schin if(fw && (w = SFWRITE(fw, cp, r)) != r)
654887Schin { if(fr->extent >= 0 )
664887Schin (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
674887Schin if(fw->extent >= 0 && w > 0)
684887Schin (void)SFSEEK(fw,(Sfoff_t)(-w),SEEK_CUR);
694887Schin n = 0;
704887Schin }
714887Schin else
724887Schin { n_move += 1;
734887Schin if(n > 0)
744887Schin n -= 1;
754887Schin }
764887Schin }
774887Schin continue;
784887Schin }
794887Schin
804887Schin /* get the streams into the right mode */
814887Schin if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
824887Schin break;
834887Schin
844887Schin SFLOCK(fr,0);
854887Schin
864887Schin /* flush the write buffer as necessary to make room */
874887Schin if(fw)
884887Schin { if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 )
894887Schin break;
904887Schin SFLOCK(fw,0);
914887Schin if(fw->next >= fw->endb ||
924887Schin (fw->next > fw->data && fr->extent < 0 &&
934887Schin (fw->extent < 0 || (fw->flags&SF_SHARE)) ) )
944887Schin if(SFFLSBUF(fw,-1) < 0 )
954887Schin break;
964887Schin }
974887Schin else if((cur = SFSEEK(fr, (Sfoff_t)0, SEEK_CUR)) >= 0 )
984887Schin { sk = n > 0 ? SFSEEK(fr, n, SEEK_CUR) : SFSEEK(fr, 0, SEEK_END);
994887Schin if(sk > cur) /* safe to skip over data in current stream */
1004887Schin { n_move += sk - cur;
1014887Schin if(n > 0)
1024887Schin n -= sk - cur;
1034887Schin continue;
1044887Schin }
1054887Schin /* else: stream unstacking may happen below */
1064887Schin }
1074887Schin
1084887Schin /* about to move all, set map to a large amount */
1094887Schin if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) )
1104887Schin { SFMVSET(fr);
1114887Schin fr->bits |= SF_SEQUENTIAL; /* sequentially access data */
1124887Schin }
1134887Schin
1144887Schin /* try reading a block of data */
1154887Schin direct = 0;
1164887Schin if((r = fr->endb - (next = fr->next)) <= 0)
1174887Schin { /* amount of data remained to be read */
1184887Schin if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0)
1194887Schin { if(fr->extent < 0)
1204887Schin w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
1214887Schin else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
1224887Schin w = SF_NMAP*SF_PAGE;
1234887Schin else w = (ssize_t)(fr->extent-fr->here);
1244887Schin }
1254887Schin
1264887Schin /* use a decent buffer for data transfer but make sure
1274887Schin that if we overread, the left over can be retrieved
1284887Schin */
1294887Schin if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) &&
1304887Schin (n < 0 || fr->extent >= 0) )
1314887Schin { reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE);
1324887Schin
1334887Schin /* direct transfer to a seekable write stream */
1344887Schin if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) )
1354887Schin { w = fw->endb - (next = fw->next);
1364887Schin direct = SF_WRITE;
1374887Schin }
1384887Schin else if(w > fr->size && maxw > fr->size)
1394887Schin { /* making our own buffer */
1404887Schin if(w >= maxw)
1414887Schin w = maxw;
1424887Schin else w = ((w+fr->size-1)/fr->size)*fr->size;
1434887Schin if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
1444887Schin rsize = w;
1454887Schin if(rbuf)
1464887Schin { next = rbuf;
1474887Schin w = rsize;
1484887Schin direct = SF_STRING;
1494887Schin }
1504887Schin }
1514887Schin }
1524887Schin
1534887Schin if(!direct)
1544887Schin { /* make sure we don't read too far ahead */
1554887Schin if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) )
1564887Schin { if((Sfoff_t)(r = fr->size) > n)
1574887Schin r = (ssize_t)n;
1584887Schin }
1594887Schin else r = -1;
1604887Schin if((r = SFFILBUF(fr,r)) <= 0)
1614887Schin break;
1624887Schin next = fr->next;
1634887Schin }
1644887Schin else
1654887Schin { /* actual amount to be read */
1664887Schin if(n > 0 && n < w)
1674887Schin w = (ssize_t)n;
1684887Schin
1694887Schin if((r = SFRD(fr,next,w,fr->disc)) > 0)
1704887Schin fr->next = fr->endb = fr->endr = fr->data;
1714887Schin else if(r == 0)
1724887Schin break; /* eof */
1734887Schin else goto again; /* popped stack */
1744887Schin }
1754887Schin }
1764887Schin
1774887Schin /* compute the extent of data to be moved */
1784887Schin endb = next+r;
1794887Schin if(n > 0)
1804887Schin { if(r > n)
1814887Schin r = (ssize_t)n;
1824887Schin n -= r;
1834887Schin }
1844887Schin n_move += r;
1854887Schin cp = next+r;
1864887Schin
1874887Schin if(!direct)
1884887Schin fr->next += r;
1894887Schin else if((w = endb-cp) > 0)
1904887Schin { /* move left-over to read stream */
1914887Schin if(w > fr->size)
1924887Schin w = fr->size;
1934887Schin memcpy((Void_t*)fr->data,(Void_t*)cp,w);
1944887Schin fr->endb = fr->data+w;
1954887Schin if((w = endb - (cp+w)) > 0)
1964887Schin (void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc);
1974887Schin }
1984887Schin
1994887Schin if(fw)
2004887Schin { if(direct == SF_WRITE)
2014887Schin fw->next += r;
2024887Schin else if(r <= (fw->endb-fw->next) )
2034887Schin { memcpy((Void_t*)fw->next,(Void_t*)next,r);
2044887Schin fw->next += r;
2054887Schin }
2064887Schin else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
2074887Schin { /* a write error happened */
2084887Schin if(w > 0)
2094887Schin { r -= w;
2104887Schin n_move -= r;
2114887Schin }
2124887Schin if(fr->extent >= 0)
2134887Schin (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
2144887Schin break;
2154887Schin }
2164887Schin }
2174887Schin
2184887Schin again:
2194887Schin SFOPEN(fr,0);
2204887Schin if(fw)
2214887Schin SFOPEN(fw,0);
2224887Schin }
2234887Schin
2244887Schin if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE))
2254887Schin { /* back to normal access mode */
2264887Schin SFMVUNSET(fr);
2274887Schin if((fr->bits&SF_SEQUENTIAL) && (fr->data))
2284887Schin SFMMSEQOFF(fr,fr->data,fr->endb-fr->data);
2294887Schin fr->bits &= ~SF_SEQUENTIAL;
2304887Schin }
2314887Schin
2324887Schin if(rbuf)
2334887Schin free(rbuf);
2344887Schin
2354887Schin if(fw)
2364887Schin { SFOPEN(fw,0);
2378462SApril.Chin@Sun.COM SFMTXEND2(fw);
2384887Schin }
2394887Schin
2408462SApril.Chin@Sun.COM SFOPEN(fr,0);
2414887Schin SFMTXRETURN(fr, n_move);
2424887Schin }
243