1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* Move data from one stream to another.
25 ** This code is written so that it'll work even in the presence
26 ** of stacking streams, pool, and discipline.
27 ** If you must change it, be gentle.
29 ** Written by Kiem-Phong Vo.
31 #define MAX_SSIZE ((ssize_t)((~((size_t)0)) >> 1))
34 Sfoff_t
sfmove(Sfio_t
* fr
, Sfio_t
* fw
, Sfoff_t n
, reg
int rc
)
36 Sfoff_t
sfmove(fr
,fw
,n
,rc
)
37 Sfio_t
* fr
; /* moving data from this stream */
38 Sfio_t
* fw
; /* moving data to this stream */
39 Sfoff_t n
; /* number of bytes/records to move. <0 for unbounded move */
40 reg
int rc
; /* record separator */
47 Sfoff_t n_move
, sk
, cur
;
48 uchar
*rbuf
= NIL(uchar
*);
53 SFMTXENTER(fr
, (Sfoff_t
)0);
55 SFMTXBEGIN2(fw
, (Sfoff_t
)0);
57 for(n_move
= 0; n
!= 0; )
59 if(rc
>= 0) /* moving records, let sfgetr() deal with record reading */
60 { if(!(cp
= (uchar
*)sfgetr(fr
,rc
,0)) )
64 if(fw
&& (w
= SFWRITE(fw
, cp
, r
)) != r
)
65 { if(fr
->extent
>= 0 )
66 (void)SFSEEK(fr
,(Sfoff_t
)(-r
),SEEK_CUR
);
67 if(fw
->extent
>= 0 && w
> 0)
68 (void)SFSEEK(fw
,(Sfoff_t
)(-w
),SEEK_CUR
);
80 /* get the streams into the right mode */
81 if(fr
->mode
!= SF_READ
&& _sfmode(fr
,SF_READ
,0) < 0)
86 /* flush the write buffer as necessary to make room */
88 { if(fw
->mode
!= SF_WRITE
&& _sfmode(fw
,SF_WRITE
,0) < 0 )
91 if(fw
->next
>= fw
->endb
||
92 (fw
->next
> fw
->data
&& fr
->extent
< 0 &&
93 (fw
->extent
< 0 || (fw
->flags
&SF_SHARE
)) ) )
94 if(SFFLSBUF(fw
,-1) < 0 )
97 else if((cur
= SFSEEK(fr
, (Sfoff_t
)0, SEEK_CUR
)) >= 0 )
98 { sk
= n
> 0 ? SFSEEK(fr
, n
, SEEK_CUR
) : SFSEEK(fr
, 0, SEEK_END
);
99 if(sk
> cur
) /* safe to skip over data in current stream */
100 { n_move
+= sk
- cur
;
105 /* else: stream unstacking may happen below */
108 /* about to move all, set map to a large amount */
109 if(n
< 0 && (fr
->bits
&SF_MMAP
) && !(fr
->bits
&SF_MVSIZE
) )
111 fr
->bits
|= SF_SEQUENTIAL
; /* sequentially access data */
114 /* try reading a block of data */
116 if((r
= fr
->endb
- (next
= fr
->next
)) <= 0)
117 { /* amount of data remained to be read */
118 if((w
= n
> MAX_SSIZE
? MAX_SSIZE
: (ssize_t
)n
) < 0)
120 w
= fr
->data
== fr
->tiny
? SF_GRAIN
: fr
->size
;
121 else if((fr
->extent
-fr
->here
) > SF_NMAP
*SF_PAGE
)
123 else w
= (ssize_t
)(fr
->extent
-fr
->here
);
126 /* use a decent buffer for data transfer but make sure
127 that if we overread, the left over can be retrieved
129 if(!(fr
->flags
&SF_STRING
) && !(fr
->bits
&SF_MMAP
) &&
130 (n
< 0 || fr
->extent
>= 0) )
131 { reg ssize_t maxw
= 4*(_Sfpage
> 0 ? _Sfpage
: SF_PAGE
);
133 /* direct transfer to a seekable write stream */
134 if(fw
&& fw
->extent
>= 0 && w
<= (fw
->endb
-fw
->next
) )
135 { w
= fw
->endb
- (next
= fw
->next
);
138 else if(w
> fr
->size
&& maxw
> fr
->size
)
139 { /* making our own buffer */
142 else w
= ((w
+fr
->size
-1)/fr
->size
)*fr
->size
;
143 if(rsize
<= 0 && (rbuf
= (uchar
*)malloc(w
)) )
154 { /* make sure we don't read too far ahead */
155 if(n
> 0 && fr
->extent
< 0 && (fr
->flags
&SF_SHARE
) )
156 { if((Sfoff_t
)(r
= fr
->size
) > n
)
160 if((r
= SFFILBUF(fr
,r
)) <= 0)
165 { /* actual amount to be read */
169 if((r
= SFRD(fr
,next
,w
,fr
->disc
)) > 0)
170 fr
->next
= fr
->endb
= fr
->endr
= fr
->data
;
173 else goto again
; /* popped stack */
177 /* compute the extent of data to be moved */
189 else if((w
= endb
-cp
) > 0)
190 { /* move left-over to read stream */
193 memcpy((Void_t
*)fr
->data
,(Void_t
*)cp
,w
);
194 fr
->endb
= fr
->data
+w
;
195 if((w
= endb
- (cp
+w
)) > 0)
196 (void)SFSK(fr
,(Sfoff_t
)(-w
),SEEK_CUR
,fr
->disc
);
200 { if(direct
== SF_WRITE
)
202 else if(r
<= (fw
->endb
-fw
->next
) )
203 { memcpy((Void_t
*)fw
->next
,(Void_t
*)next
,r
);
206 else if((w
= SFWRITE(fw
,(Void_t
*)next
,r
)) != r
)
207 { /* a write error happened */
213 (void)SFSEEK(fr
,(Sfoff_t
)(-r
),SEEK_CUR
);
224 if(n
< 0 && (fr
->bits
&SF_MMAP
) && (fr
->bits
&SF_MVSIZE
))
225 { /* back to normal access mode */
227 if((fr
->bits
&SF_SEQUENTIAL
) && (fr
->data
))
228 SFMMSEQOFF(fr
,fr
->data
,fr
->endb
-fr
->data
);
229 fr
->bits
&= ~SF_SEQUENTIAL
;
241 SFMTXRETURN(fr
, n_move
);