1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 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 51 SFMTXSTART(fr, (Sfoff_t)0); 52 if(fw) 53 SFMTXLOCK(fw); 54 55 for(n_move = 0; n != 0; ) 56 { 57 if(rc >= 0) /* moving records, let sfgetr() deal with record reading */ 58 { if(!(cp = (uchar*)sfgetr(fr,rc,0)) ) 59 n = 0; 60 else 61 { r = sfvalue(fr); 62 if(fw && (w = SFWRITE(fw, cp, r)) != r) 63 { if(fr->extent >= 0 ) 64 (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR); 65 if(fw->extent >= 0 && w > 0) 66 (void)SFSEEK(fw,(Sfoff_t)(-w),SEEK_CUR); 67 n = 0; 68 } 69 else 70 { n_move += 1; 71 if(n > 0) 72 n -= 1; 73 } 74 } 75 continue; 76 } 77 78 /* get the streams into the right mode */ 79 if(fr->mode != SF_READ && _sfmode(fr,SF_READ,0) < 0) 80 break; 81 82 SFLOCK(fr,0); 83 84 /* flush the write buffer as necessary to make room */ 85 if(fw) 86 { if(fw->mode != SF_WRITE && _sfmode(fw,SF_WRITE,0) < 0 ) 87 break; 88 SFLOCK(fw,0); 89 if(fw->next >= fw->endb || 90 (fw->next > fw->data && fr->extent < 0 && 91 (fw->extent < 0 || (fw->flags&SF_SHARE)) ) ) 92 if(SFFLSBUF(fw,-1) < 0 ) 93 break; 94 } 95 else if((cur = SFSEEK(fr, (Sfoff_t)0, SEEK_CUR)) >= 0 ) 96 { sk = n > 0 ? SFSEEK(fr, n, SEEK_CUR) : SFSEEK(fr, 0, SEEK_END); 97 if(sk > cur) /* safe to skip over data in current stream */ 98 { n_move += sk - cur; 99 if(n > 0) 100 n -= sk - cur; 101 continue; 102 } 103 /* else: stream unstacking may happen below */ 104 } 105 106 /* about to move all, set map to a large amount */ 107 if(n < 0 && (fr->bits&SF_MMAP) && !(fr->bits&SF_MVSIZE) ) 108 { SFMVSET(fr); 109 fr->bits |= SF_SEQUENTIAL; /* sequentially access data */ 110 } 111 112 /* try reading a block of data */ 113 direct = 0; 114 if((r = fr->endb - (next = fr->next)) <= 0) 115 { /* amount of data remained to be read */ 116 if((w = n > MAX_SSIZE ? MAX_SSIZE : (ssize_t)n) < 0) 117 { if(fr->extent < 0) 118 w = fr->data == fr->tiny ? SF_GRAIN : fr->size; 119 else if((fr->extent-fr->here) > SF_NMAP*SF_PAGE) 120 w = SF_NMAP*SF_PAGE; 121 else w = (ssize_t)(fr->extent-fr->here); 122 } 123 124 /* use a decent buffer for data transfer but make sure 125 that if we overread, the left over can be retrieved 126 */ 127 if(!(fr->flags&SF_STRING) && !(fr->bits&SF_MMAP) && 128 (n < 0 || fr->extent >= 0) ) 129 { reg ssize_t maxw = 4*(_Sfpage > 0 ? _Sfpage : SF_PAGE); 130 131 /* direct transfer to a seekable write stream */ 132 if(fw && fw->extent >= 0 && w <= (fw->endb-fw->next) ) 133 { w = fw->endb - (next = fw->next); 134 direct = SF_WRITE; 135 } 136 else if(w > fr->size && maxw > fr->size) 137 { /* making our own buffer */ 138 if(w >= maxw) 139 w = maxw; 140 else w = ((w+fr->size-1)/fr->size)*fr->size; 141 if(rsize <= 0 && (rbuf = (uchar*)malloc(w)) ) 142 rsize = w; 143 if(rbuf) 144 { next = rbuf; 145 w = rsize; 146 direct = SF_STRING; 147 } 148 } 149 } 150 151 if(!direct) 152 { /* make sure we don't read too far ahead */ 153 if(n > 0 && fr->extent < 0 && (fr->flags&SF_SHARE) ) 154 { if((Sfoff_t)(r = fr->size) > n) 155 r = (ssize_t)n; 156 } 157 else r = -1; 158 if((r = SFFILBUF(fr,r)) <= 0) 159 break; 160 next = fr->next; 161 } 162 else 163 { /* actual amount to be read */ 164 if(n > 0 && n < w) 165 w = (ssize_t)n; 166 167 if((r = SFRD(fr,next,w,fr->disc)) > 0) 168 fr->next = fr->endb = fr->endr = fr->data; 169 else if(r == 0) 170 break; /* eof */ 171 else goto again; /* popped stack */ 172 } 173 } 174 175 /* compute the extent of data to be moved */ 176 endb = next+r; 177 if(n > 0) 178 { if(r > n) 179 r = (ssize_t)n; 180 n -= r; 181 } 182 n_move += r; 183 cp = next+r; 184 185 if(!direct) 186 fr->next += r; 187 else if((w = endb-cp) > 0) 188 { /* move left-over to read stream */ 189 if(w > fr->size) 190 w = fr->size; 191 memcpy((Void_t*)fr->data,(Void_t*)cp,w); 192 fr->endb = fr->data+w; 193 if((w = endb - (cp+w)) > 0) 194 (void)SFSK(fr,(Sfoff_t)(-w),SEEK_CUR,fr->disc); 195 } 196 197 if(fw) 198 { if(direct == SF_WRITE) 199 fw->next += r; 200 else if(r <= (fw->endb-fw->next) ) 201 { memcpy((Void_t*)fw->next,(Void_t*)next,r); 202 fw->next += r; 203 } 204 else if((w = SFWRITE(fw,(Void_t*)next,r)) != r) 205 { /* a write error happened */ 206 if(w > 0) 207 { r -= w; 208 n_move -= r; 209 } 210 if(fr->extent >= 0) 211 (void)SFSEEK(fr,(Sfoff_t)(-r),SEEK_CUR); 212 break; 213 } 214 } 215 216 again: 217 SFOPEN(fr,0); 218 if(fw) 219 SFOPEN(fw,0); 220 } 221 222 if(n < 0 && (fr->bits&SF_MMAP) && (fr->bits&SF_MVSIZE)) 223 { /* back to normal access mode */ 224 SFMVUNSET(fr); 225 if((fr->bits&SF_SEQUENTIAL) && (fr->data)) 226 SFMMSEQOFF(fr,fr->data,fr->endb-fr->data); 227 fr->bits &= ~SF_SEQUENTIAL; 228 } 229 230 if(rbuf) 231 free(rbuf); 232 233 SFOPEN(fr,0); 234 if(fw) 235 { SFOPEN(fw,0); 236 SFMTXUNLOCK(fw); 237 } 238 239 SFMTXRETURN(fr, n_move); 240 } 241