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