1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2013 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <glenn.s.fowler@gmail.com> * 18 * David Korn <dgkorn@gmail.com> * 19 * Phong Vo <phongvo@gmail.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 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); /* declare a shadow stream variable for from stream */ 51 SFMTXDECL2(fw); /* declare a shadow stream variable for to stream */ 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(fr->rsrv && (r = -fr->rsrv->slen) > 0) 117 { fr->rsrv->slen = 0; 118 next = fr->rsrv->data; 119 } 120 else if((r = fr->endb - (next = fr->next)) <= 0) 121 { /* amount of data remained to be read */ 122 if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0) 123 { if(fr->extent < 0) 124 w = fr->data == fr->tiny ? SF_GRAIN : fr->size; 125 else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE) 126 w = SF_NMAP*SF_PAGE; 127 else w = (ssize_t)(fr->extent-fr->here); 128 } 129 130 /* use a decent buffer for data transfer but make sure 131 that if we overread, the left over can be retrieved 132 */ 133 if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) && 134 (n < 0 || fr->extent >= 0) ) 135 { reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE); 136 137 /* direct transfer to a seekable write stream */ 138 if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) ) 139 { w = fw->endb - (next = fw->next); 140 direct = SF_WRITE; 141 } 142 else if(w > fr->size && maxw > fr->size) 143 { /* making our own buffer */ 144 if(w >= maxw) 145 w = maxw; 146 else w = ((w+fr->size-1)/fr->size)*fr->size; 147 if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) ) 148 rsize = w; 149 if(rbuf) 150 { next = rbuf; 151 w = rsize; 152 direct = SF_STRING; 153 } 154 } 155 } 156 157 if(!direct) 158 { /* make sure we don't read too far ahead */ 159 if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) ) 160 { if((Sfoff_t)(r = fr->size) > n) 161 r = (ssize_t)n; 162 } 163 else r = -1; 164 if((r = SFFILBUF(fr,r)) <= 0) 165 break; 166 next = fr->next; 167 } 168 else 169 { /* actual amount to be read */ 170 if(n > 0 && n < w) 171 w = (ssize_t)n; 172 173 if((r = SFRD(fr,next,w,fr->disc)) > 0) 174 fr->next = fr->endb = fr->endr = fr->data; 175 else if(r == 0) 176 break; /* eof */ 177 else goto again; /* popped stack */ 178 } 179 } 180 181 /* compute the extent of data to be moved */ 182 endb = next+r; 183 if(n > 0) 184 { if(r > n) 185 r = (ssize_t)n; 186 n -= r; 187 } 188 n_move += r; 189 cp = next+r; 190 191 if(!direct) 192 fr->next += r; 193 else if((w = endb-cp) > 0) 194 { /* move left-over to read stream */ 195 if(w > fr->size) 196 w = fr->size; 197 memcpy((Void_t*)fr->data,(Void_t*)cp,w); 198 fr->endb = fr->data+w; 199 if((w = endb - (cp+w)) > 0) 200 (void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc); 201 } 202 203 if(fw) 204 { if(direct == SF_WRITE) 205 fw->next += r; 206 else if(r <= (fw->endb-fw->next) ) 207 { memcpy((Void_t*)fw->next,(Void_t*)next,r); 208 fw->next += r; 209 } 210 else if((w = SFWRITE(fw,(Void_t*)next,r)) != r) 211 { /* a write error happened */ 212 if(w > 0) 213 { r -= w; 214 n_move -= r; 215 } 216 if(fr->extent >= 0) 217 (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR); 218 break; 219 } 220 } 221 222 again: 223 SFOPEN(fr,0); 224 if(fw) 225 SFOPEN(fw,0); 226 } 227 228 if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE)) 229 { /* back to normal access mode */ 230 SFMVUNSET(fr); 231 if((fr->bits&SF_SEQUENTIAL) && (fr->data)) 232 SFMMSEQOFF(fr,fr->data,fr->endb-fr->data); 233 fr->bits &= ~SF_SEQUENTIAL; 234 } 235 236 if(rbuf) 237 free(rbuf); 238 239 if(fw) 240 { SFOPEN(fw,0); 241 SFMTXEND2(fw); 242 } 243 244 SFOPEN(fr,0); 245 SFMTXRETURN(fr, n_move); 246 } 247