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 "sfdchdr.h" 23 24 25 /* Discipline to treat a contiguous segment of a stream as a stream 26 ** in its own right. The hard part in all this is to allow multiple 27 ** segments of the stream to be used as substreams at the same time. 28 ** 29 ** Written by David G. Korn and Kiem-Phong Vo (03/18/1998) 30 */ 31 32 typedef struct _subfile_s 33 { 34 Sfdisc_t disc; /* sfio discipline */ 35 Sfio_t* parent; /* parent stream */ 36 Sfoff_t offset; /* starting offset */ 37 Sfoff_t extent; /* size wanted */ 38 Sfoff_t here; /* current seek location */ 39 } Subfile_t; 40 41 #if __STD_C 42 static ssize_t streamio(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc, int type) 43 #else 44 static ssize_t streamio(f, buf, n, disc, type) 45 Sfio_t* f; 46 Void_t* buf; 47 size_t n; 48 Sfdisc_t* disc; 49 int type; 50 #endif 51 { 52 reg Subfile_t *su; 53 reg Sfoff_t here, parent; 54 reg ssize_t io; 55 56 su = (Subfile_t*)disc; 57 58 /* read just what we need */ 59 if(su->extent >= 0 && (ssize_t)n > (io = (ssize_t)(su->extent - su->here)) ) 60 n = io; 61 if(n <= 0) 62 return n; 63 64 /* save current location in parent stream */ 65 parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc); 66 67 /* read data */ 68 here = su->here + su->offset; 69 if(sfsk(f,here,SEEK_SET,disc) != here) 70 io = 0; 71 else 72 { if(type == SF_WRITE) 73 io = sfwr(f,buf,n,disc); 74 else io = sfrd(f,buf,n,disc); 75 if(io > 0) 76 su->here += io; 77 } 78 79 /* restore parent current position */ 80 sfsk(f,parent,SEEK_SET,disc); 81 82 return io; 83 } 84 85 #if __STD_C 86 static ssize_t streamwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc) 87 #else 88 static ssize_t streamwrite(f, buf, n, disc) 89 Sfio_t* f; 90 Void_t* buf; 91 size_t n; 92 Sfdisc_t* disc; 93 #endif 94 { 95 return streamio(f,(Void_t*)buf,n,disc,SF_WRITE); 96 } 97 98 #if __STD_C 99 static ssize_t streamread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc) 100 #else 101 static ssize_t streamread(f, buf, n, disc) 102 Sfio_t* f; 103 Void_t* buf; 104 size_t n; 105 Sfdisc_t* disc; 106 #endif 107 { 108 return streamio(f,buf,n,disc,SF_READ); 109 } 110 111 #if __STD_C 112 static Sfoff_t streamseek(Sfio_t* f, Sfoff_t pos, int type, Sfdisc_t* disc) 113 #else 114 static Sfoff_t streamseek(f, pos, type, disc) 115 Sfio_t* f; 116 Sfoff_t pos; 117 int type; 118 Sfdisc_t* disc; 119 #endif 120 { 121 reg Subfile_t* su; 122 reg Sfoff_t here, parent; 123 124 su = (Subfile_t*)disc; 125 126 switch(type) 127 { 128 case SEEK_SET: 129 here = 0; 130 break; 131 case SEEK_CUR: 132 here = su->here; 133 break; 134 case SEEK_END: 135 if(su->extent >= 0) 136 here = su->extent; 137 else 138 { parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc); 139 if((here = sfsk(f,(Sfoff_t)0,SEEK_END,disc)) < 0) 140 return -1; 141 else here -= su->offset; 142 sfsk(f,parent,SEEK_SET,disc); 143 } 144 break; 145 default: 146 return -1; 147 } 148 149 pos += here; 150 if(pos < 0 || (su->extent >= 0 && pos >= su->extent)) 151 return -1; 152 153 return (su->here = pos); 154 } 155 156 #if __STD_C 157 static int streamexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc) 158 #else 159 static int streamexcept(f, type, data, disc) 160 Sfio_t* f; 161 int type; 162 Void_t* data; 163 Sfdisc_t* disc; 164 #endif 165 { 166 if(type == SF_FINAL || type == SF_DPOP) 167 free(disc); 168 return 0; 169 } 170 171 #if __STD_C 172 Sfio_t* sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t extent) 173 #else 174 Sfio_t* sfdcsubstream(f, parent, offset, extent) 175 Sfio_t* f; /* stream */ 176 Sfio_t* parent; /* parent stream */ 177 Sfoff_t offset; /* offset in f */ 178 Sfoff_t extent; /* desired size */ 179 #endif 180 { 181 reg Sfio_t* sp; 182 reg Subfile_t* su; 183 reg Sfoff_t here; 184 185 /* establish that we can seek to offset */ 186 if((here = sfseek(parent,(Sfoff_t)0,SEEK_CUR)) < 0 || sfseek(parent,offset,SEEK_SET) < 0) 187 return 0; 188 else sfseek(parent,here,SEEK_SET); 189 sfpurge(parent); 190 191 if (!(sp = f) && !(sp = sfnew(NIL(Sfio_t*), NIL(Void_t*), (size_t)SF_UNBOUND, dup(sffileno(parent)), parent->flags))) 192 return 0; 193 194 if(!(su = (Subfile_t*)malloc(sizeof(Subfile_t)))) 195 { if(sp != f) 196 sfclose(sp); 197 return 0; 198 } 199 memset(su, 0, sizeof(*su)); 200 201 su->disc.readf = streamread; 202 su->disc.writef = streamwrite; 203 su->disc.seekf = streamseek; 204 su->disc.exceptf = streamexcept; 205 su->parent = parent; 206 su->offset = offset; 207 su->extent = extent; 208 209 if(sfdisc(sp, (Sfdisc_t*)su) != (Sfdisc_t*)su) 210 { free(su); 211 if(sp != f) 212 sfclose(sp); 213 return 0; 214 } 215 216 return sp; 217 } 218