1 /***********************************************************************
2 * *
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 *
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 /* 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.
28 **
29 ** Written by Kiem-Phong Vo.
30 */
31 #define MAX_SSIZE ((ssize_t)((~((size_t)0)) >> 1))
32
33 #if __STD_C
sfmove(Sfio_t * fr,Sfio_t * fw,Sfoff_t n,reg int rc)34 Sfoff_t sfmove(Sfio_t* fr, Sfio_t* fw, Sfoff_t n, reg int rc)
35 #else
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 */
41 #endif
42 {
43 reg uchar *cp, *next;
44 reg ssize_t r, w;
45 reg uchar *endb;
46 reg int direct;
47 Sfoff_t n_move, sk, cur;
48 uchar *rbuf = NIL(uchar*);
49 ssize_t rsize = 0;
50 SFMTXDECL(fr);
51 SFMTXDECL2(fw);
52
53 SFMTXENTER(fr, (Sfoff_t)0);
54 if(fw)
55 SFMTXBEGIN2(fw, (Sfoff_t)0);
56
57 for(n_move = 0; n != 0; )
58 {
59 if(rc >= 0) /* moving records, let sfgetr() deal with record reading */
60 { if(!(cp = (uchar*)sfgetr(fr,rc,0)) )
61 n = 0;
62 else
63 { r = sfvalue(fr);
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);
69 n = 0;
70 }
71 else
72 { n_move += 1;
73 if(n > 0)
74 n -= 1;
75 }
76 }
77 continue;
78 }
79
80 /* get the streams into the right mode */
81 if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0)
82 break;
83
84 SFLOCK(fr,0);
85
86 /* flush the write buffer as necessary to make room */
87 if(fw)
88 { if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 )
89 break;
90 SFLOCK(fw,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 )
95 break;
96 }
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;
101 if(n > 0)
102 n -= sk - cur;
103 continue;
104 }
105 /* else: stream unstacking may happen below */
106 }
107
108 /* about to move all, set map to a large amount */
109 if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) )
110 { SFMVSET(fr);
111 fr->bits |= SF_SEQUENTIAL; /* sequentially access data */
112 }
113
114 /* try reading a block of data */
115 direct = 0;
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)
119 { if(fr->extent < 0)
120 w = fr->data == fr->tiny ? SF_GRAIN : fr->size;
121 else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE)
122 w = SF_NMAP*SF_PAGE;
123 else w = (ssize_t)(fr->extent-fr->here);
124 }
125
126 /* use a decent buffer for data transfer but make sure
127 that if we overread, the left over can be retrieved
128 */
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);
132
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);
136 direct = SF_WRITE;
137 }
138 else if(w > fr->size && maxw > fr->size)
139 { /* making our own buffer */
140 if(w >= maxw)
141 w = maxw;
142 else w = ((w+fr->size-1)/fr->size)*fr->size;
143 if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) )
144 rsize = w;
145 if(rbuf)
146 { next = rbuf;
147 w = rsize;
148 direct = SF_STRING;
149 }
150 }
151 }
152
153 if(!direct)
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)
157 r = (ssize_t)n;
158 }
159 else r = -1;
160 if((r = SFFILBUF(fr,r)) <= 0)
161 break;
162 next = fr->next;
163 }
164 else
165 { /* actual amount to be read */
166 if(n > 0 && n < w)
167 w = (ssize_t)n;
168
169 if((r = SFRD(fr,next,w,fr->disc)) > 0)
170 fr->next = fr->endb = fr->endr = fr->data;
171 else if(r == 0)
172 break; /* eof */
173 else goto again; /* popped stack */
174 }
175 }
176
177 /* compute the extent of data to be moved */
178 endb = next+r;
179 if(n > 0)
180 { if(r > n)
181 r = (ssize_t)n;
182 n -= r;
183 }
184 n_move += r;
185 cp = next+r;
186
187 if(!direct)
188 fr->next += r;
189 else if((w = endb-cp) > 0)
190 { /* move left-over to read stream */
191 if(w > fr->size)
192 w = fr->size;
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);
197 }
198
199 if(fw)
200 { if(direct == SF_WRITE)
201 fw->next += r;
202 else if(r <= (fw->endb-fw->next) )
203 { memcpy((Void_t*)fw->next,(Void_t*)next,r);
204 fw->next += r;
205 }
206 else if((w = SFWRITE(fw,(Void_t*)next,r)) != r)
207 { /* a write error happened */
208 if(w > 0)
209 { r -= w;
210 n_move -= r;
211 }
212 if(fr->extent >= 0)
213 (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR);
214 break;
215 }
216 }
217
218 again:
219 SFOPEN(fr,0);
220 if(fw)
221 SFOPEN(fw,0);
222 }
223
224 if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE))
225 { /* back to normal access mode */
226 SFMVUNSET(fr);
227 if((fr->bits&SF_SEQUENTIAL) && (fr->data))
228 SFMMSEQOFF(fr,fr->data,fr->endb-fr->data);
229 fr->bits &= ~SF_SEQUENTIAL;
230 }
231
232 if(rbuf)
233 free(rbuf);
234
235 if(fw)
236 { SFOPEN(fw,0);
237 SFMTXEND2(fw);
238 }
239
240 SFOPEN(fr,0);
241 SFMTXRETURN(fr, n_move);
242 }
243