1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 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 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