1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #include "sfdchdr.h" 23*4887Schin 24*4887Schin /* Discipline to make an unseekable read stream seekable 25*4887Schin ** 26*4887Schin ** sfraise(f,SFSK_DISCARD,0) discards previous seek data 27*4887Schin ** but seeks from current offset on still allowed 28*4887Schin ** 29*4887Schin ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998. 30*4887Schin */ 31*4887Schin 32*4887Schin typedef struct _skable_s 33*4887Schin { Sfdisc_t disc; /* sfio discipline */ 34*4887Schin Sfio_t* shadow; /* to shadow data */ 35*4887Schin Sfoff_t discard;/* sfseek(f,-1,SEEK_SET) discarded data */ 36*4887Schin Sfoff_t extent; /* shadow extent */ 37*4887Schin int eof; /* if eof has been reached */ 38*4887Schin } Seek_t; 39*4887Schin 40*4887Schin #if __STD_C 41*4887Schin static ssize_t skwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc) 42*4887Schin #else 43*4887Schin static ssize_t skwrite(f, buf, n, disc) 44*4887Schin Sfio_t* f; /* stream involved */ 45*4887Schin Void_t* buf; /* buffer to read into */ 46*4887Schin size_t n; /* number of bytes to read */ 47*4887Schin Sfdisc_t* disc; /* discipline */ 48*4887Schin #endif 49*4887Schin { 50*4887Schin return (ssize_t)(-1); 51*4887Schin } 52*4887Schin 53*4887Schin #if __STD_C 54*4887Schin static ssize_t skread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc) 55*4887Schin #else 56*4887Schin static ssize_t skread(f, buf, n, disc) 57*4887Schin Sfio_t* f; /* stream involved */ 58*4887Schin Void_t* buf; /* buffer to read into */ 59*4887Schin size_t n; /* number of bytes to read */ 60*4887Schin Sfdisc_t* disc; /* discipline */ 61*4887Schin #endif 62*4887Schin { 63*4887Schin Seek_t* sk; 64*4887Schin Sfio_t* sf; 65*4887Schin Sfoff_t addr; 66*4887Schin ssize_t r, w, p; 67*4887Schin 68*4887Schin sk = (Seek_t*)disc; 69*4887Schin sf = sk->shadow; 70*4887Schin if(sk->eof) 71*4887Schin return sfread(sf,buf,n); 72*4887Schin 73*4887Schin addr = sfseek(sf,(Sfoff_t)0,SEEK_CUR); 74*4887Schin 75*4887Schin if(addr+n <= sk->extent) 76*4887Schin return sfread(sf,buf,n); 77*4887Schin 78*4887Schin if((r = (ssize_t)(sk->extent-addr)) > 0) 79*4887Schin { if((w = sfread(sf,buf,r)) != r) 80*4887Schin return w; 81*4887Schin buf = (char*)buf + r; 82*4887Schin n -= r; 83*4887Schin } 84*4887Schin 85*4887Schin /* do a raw read */ 86*4887Schin if((w = sfrd(f,buf,n,disc)) <= 0) 87*4887Schin { sk->eof = 1; 88*4887Schin w = 0; 89*4887Schin } 90*4887Schin else 91*4887Schin { 92*4887Schin if((p = sfwrite(sf,buf,w)) != w) 93*4887Schin sk->eof = 1; 94*4887Schin if(p > 0) 95*4887Schin sk->extent += p; 96*4887Schin } 97*4887Schin 98*4887Schin return r+w; 99*4887Schin } 100*4887Schin 101*4887Schin #if __STD_C 102*4887Schin static Sfoff_t skseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc) 103*4887Schin #else 104*4887Schin static Sfoff_t skseek(f, addr, type, disc) 105*4887Schin Sfio_t* f; 106*4887Schin Sfoff_t addr; 107*4887Schin int type; 108*4887Schin Sfdisc_t* disc; 109*4887Schin #endif 110*4887Schin { 111*4887Schin Seek_t* sk; 112*4887Schin Sfio_t* sf; 113*4887Schin char buf[SF_BUFSIZE]; 114*4887Schin ssize_t r, w; 115*4887Schin 116*4887Schin sk = (Seek_t*)disc; 117*4887Schin sf = sk->shadow; 118*4887Schin 119*4887Schin switch (type) 120*4887Schin { 121*4887Schin case SEEK_SET: 122*4887Schin addr -= sk->discard; 123*4887Schin break; 124*4887Schin case SEEK_CUR: 125*4887Schin addr += sftell(sf); 126*4887Schin break; 127*4887Schin case SEEK_END: 128*4887Schin addr += sk->extent; 129*4887Schin break; 130*4887Schin default: 131*4887Schin return -1; 132*4887Schin } 133*4887Schin 134*4887Schin if(addr < 0) 135*4887Schin return (Sfoff_t)(-1); 136*4887Schin else if(addr > sk->extent) 137*4887Schin { if(sk->eof) 138*4887Schin return (Sfoff_t)(-1); 139*4887Schin 140*4887Schin /* read enough to reach the seek point */ 141*4887Schin while(addr > sk->extent) 142*4887Schin { if(addr > sk->extent+sizeof(buf) ) 143*4887Schin w = sizeof(buf); 144*4887Schin else w = (int)(addr-sk->extent); 145*4887Schin if((r = sfrd(f,buf,w,disc)) <= 0) 146*4887Schin w = r-1; 147*4887Schin else if((w = sfwrite(sf,buf,r)) > 0) 148*4887Schin sk->extent += w; 149*4887Schin if(w != r) 150*4887Schin { sk->eof = 1; 151*4887Schin break; 152*4887Schin } 153*4887Schin } 154*4887Schin 155*4887Schin if(addr > sk->extent) 156*4887Schin return (Sfoff_t)(-1); 157*4887Schin } 158*4887Schin 159*4887Schin return sfseek(sf,addr,SEEK_SET) + sk->discard; 160*4887Schin } 161*4887Schin 162*4887Schin /* on close, remove the discipline */ 163*4887Schin #if __STD_C 164*4887Schin static int skexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc) 165*4887Schin #else 166*4887Schin static int skexcept(f,type,data,disc) 167*4887Schin Sfio_t* f; 168*4887Schin int type; 169*4887Schin Void_t* data; 170*4887Schin Sfdisc_t* disc; 171*4887Schin #endif 172*4887Schin { 173*4887Schin Seek_t* sk; 174*4887Schin 175*4887Schin sk = (Seek_t*)disc; 176*4887Schin 177*4887Schin switch (type) 178*4887Schin { 179*4887Schin case SF_FINAL: 180*4887Schin case SF_DPOP: 181*4887Schin sfclose(sk->shadow); 182*4887Schin free(disc); 183*4887Schin break; 184*4887Schin case SFSK_DISCARD: 185*4887Schin sk->eof = 0; 186*4887Schin sk->discard += sk->extent; 187*4887Schin sk->extent = 0; 188*4887Schin sfseek(sk->shadow,(Sfoff_t)0,SEEK_SET); 189*4887Schin break; 190*4887Schin } 191*4887Schin return 0; 192*4887Schin } 193*4887Schin 194*4887Schin #if __STD_C 195*4887Schin int sfdcseekable(Sfio_t* f) 196*4887Schin #else 197*4887Schin int sfdcseekable(f) 198*4887Schin Sfio_t* f; 199*4887Schin #endif 200*4887Schin { 201*4887Schin reg Seek_t* sk; 202*4887Schin 203*4887Schin /* see if already seekable */ 204*4887Schin if(sfseek(f,(Sfoff_t)0,SEEK_CUR) >= 0) 205*4887Schin return 0; 206*4887Schin 207*4887Schin if(!(sk = (Seek_t*)malloc(sizeof(Seek_t))) ) 208*4887Schin return -1; 209*4887Schin memset(sk, 0, sizeof(*sk)); 210*4887Schin 211*4887Schin sk->disc.readf = skread; 212*4887Schin sk->disc.writef = skwrite; 213*4887Schin sk->disc.seekf = skseek; 214*4887Schin sk->disc.exceptf = skexcept; 215*4887Schin sk->shadow = sftmp(SF_BUFSIZE); 216*4887Schin sk->discard = 0; 217*4887Schin sk->extent = 0; 218*4887Schin sk->eof = 0; 219*4887Schin 220*4887Schin if(sfdisc(f, (Sfdisc_t*)sk) != (Sfdisc_t*)sk) 221*4887Schin { sfclose(sk->shadow); 222*4887Schin free(sk); 223*4887Schin return -1; 224*4887Schin } 225*4887Schin 226*4887Schin return 0; 227*4887Schin } 228