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 /* Set the IO pointer to a specific location in the stream 25 ** 26 ** Written by Kiem-Phong Vo. 27 */ 28 29 #if __STD_C 30 static void newpos(Sfio_t* f, Sfoff_t p) 31 #else 32 static void newpos(f, p) 33 Sfio_t* f; 34 Sfoff_t p; 35 #endif 36 { 37 #ifdef MAP_TYPE 38 if((f->bits&SF_MMAP) && f->data) 39 { SFMUNMAP(f, f->data, f->endb-f->data); 40 f->data = NIL(uchar*); 41 } 42 #endif 43 f->next = f->endr = f->endw = f->data; 44 f->endb = (f->mode&SF_WRITE) ? f->data+f->size : f->data; 45 if((f->here = p) < 0) 46 { f->extent = -1; 47 f->here = 0; 48 } 49 } 50 51 #if __STD_C 52 Sfoff_t sfseek(Sfio_t* f, Sfoff_t p, int type) 53 #else 54 Sfoff_t sfseek(f,p,type) 55 Sfio_t* f; /* seek to a new location in this stream */ 56 Sfoff_t p; /* place to seek to */ 57 int type; /* 0: from org, 1: from here, 2: from end */ 58 #endif 59 { 60 Sfoff_t r, s; 61 int mode, local, hardseek, mustsync; 62 63 SFMTXSTART(f, (Sfoff_t)(-1)); 64 65 GETLOCAL(f,local); 66 67 hardseek = (type|f->flags)&(SF_SHARE|SF_PUBLIC); 68 69 if(hardseek && f->mode == (SF_READ|SF_SYNCED) ) 70 { newpos(f,f->here); 71 f->mode = SF_READ; 72 } 73 74 /* set and initialize the stream to a definite mode */ 75 if((int)SFMODE(f,local) != (mode = f->mode&SF_RDWR)) 76 { int flags = f->flags; 77 78 if(hardseek&SF_PUBLIC) /* seek ptr must follow file descriptor */ 79 f->flags |= SF_SHARE|SF_PUBLIC; 80 mode = _sfmode(f,mode,local); 81 if(hardseek&SF_PUBLIC) 82 f->flags = flags; 83 84 if(mode < 0) 85 SFMTXRETURN(f, (Sfoff_t)(-1)); 86 } 87 88 mustsync = (type&SF_SHARE) && !(type&SF_PUBLIC) && 89 (f->mode&SF_READ) && !(f->flags&SF_STRING); 90 91 /* Xopen-compliant */ 92 if((type &= (SEEK_SET|SEEK_CUR|SEEK_END)) != SEEK_SET && 93 type != SEEK_CUR && type != SEEK_END ) 94 { errno = EINVAL; 95 SFMTXRETURN(f, (Sfoff_t)(-1)); 96 } 97 98 if(f->extent < 0) 99 { /* let system call set errno */ 100 (void)SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc); 101 SFMTXRETURN(f, (Sfoff_t)(-1)); 102 } 103 104 /* throw away ungetc data */ 105 if(f->disc == _Sfudisc) 106 (void)sfclose((*_Sfstack)(f,NIL(Sfio_t*))); 107 108 /* lock the stream for internal manipulations */ 109 SFLOCK(f,local); 110 111 /* clear error and eof bits */ 112 f->flags &= ~(SF_EOF|SF_ERROR); 113 114 while(f->flags&SF_STRING) 115 { SFSTRSIZE(f); 116 117 if(type == SEEK_CUR) 118 r = p + (f->next - f->data); 119 else if(type == SEEK_END) 120 r = p + f->extent; 121 else r = p; 122 123 if(r >= 0 && r <= f->size) 124 { p = r; 125 f->next = f->data+p; 126 f->here = p; 127 if(p > f->extent) 128 memclear((char*)(f->data+f->extent),(int)(p-f->extent)); 129 goto done; 130 } 131 132 /* check exception handler, note that this may pop stream */ 133 if(SFSK(f,r,SEEK_SET,f->disc) != r) 134 { p = -1; 135 goto done; 136 } 137 else if(!(f->flags&SF_STRING)) 138 { p = r; 139 goto done; 140 } 141 } 142 143 if(f->mode&SF_WRITE) 144 { /* see if we can avoid flushing buffer */ 145 if(!hardseek && type < SEEK_END && !(f->flags&SF_APPENDWR) ) 146 { s = f->here + (f->next - f->data); 147 r = p + (type == SEEK_SET ? 0 : s); 148 if(r == s) 149 { p = r; 150 goto done; 151 } 152 } 153 154 if(f->next > f->data && SFSYNC(f) < 0) 155 { p = -1; 156 goto done; 157 } 158 } 159 160 if(type == SEEK_END || (f->mode&SF_WRITE) ) 161 { if((hardseek&SF_PUBLIC) || type == SEEK_END) 162 p = SFSK(f, p, type, f->disc); 163 else 164 { r = p + (type == SEEK_CUR ? f->here : 0); 165 p = (hardseek || r != f->here) ? SFSK(f,r,SEEK_SET,f->disc) : r; 166 } 167 if(p >= 0) 168 newpos(f,p); 169 170 goto done; 171 } 172 173 /* if get here, must be a read stream */ 174 s = f->here - (f->endb - f->next); 175 r = p + (type == SEEK_CUR ? s : 0); 176 if(r <= f->here && r >= (f->here - (f->endb-f->data)) ) 177 { if((hardseek || (type == SEEK_CUR && p == 0)) ) 178 { if((s = SFSK(f, (Sfoff_t)0, SEEK_CUR, f->disc)) == f->here || 179 (s >= 0 && !(hardseek&SF_PUBLIC) && 180 (s = SFSK(f, f->here, SEEK_SET, f->disc)) == f->here) ) 181 goto near_done; 182 else if(s < 0) 183 { p = -1; 184 goto done; 185 } 186 else 187 { newpos(f,s); 188 hardseek = 0; 189 } 190 } 191 else 192 { near_done: 193 f->next = f->endb - (f->here - r); 194 p = r; 195 goto done; 196 } 197 } 198 199 /* desired position */ 200 if((p += type == SEEK_CUR ? s : 0) < 0) 201 goto done; 202 203 #ifdef MAP_TYPE 204 if(f->bits&SF_MMAP) 205 { /* if mmap is not great, stop mmaping if moving around too much */ 206 #if _mmap_worthy < 2 207 if((f->next - f->data) < ((f->endb - f->data)/4) ) 208 { SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 209 hardseek = 1; /* this forces a hard seek below */ 210 } 211 else 212 #endif 213 { /* for mmap, f->here can be virtual except for hardseek */ 214 newpos(f,p); 215 if(!hardseek) 216 goto done; 217 } 218 } 219 #endif 220 221 if(f->endb > f->next) 222 { /* reduce wastage in future buffer fillings */ 223 f->iosz = (f->next - f->data) + (f->endb - f->next)/2; 224 f->iosz = ((f->iosz + f->blksz-1)/f->blksz)*f->blksz; 225 } 226 if(f->iosz >= f->size) 227 f->iosz = 0; 228 229 /* buffer is now considered empty */ 230 f->next = f->endr = f->endb = f->data; 231 232 /* small backseeks often come in bunches, so seek back as far as possible */ 233 if(p < f->lpos && f->size > f->blksz && (p + f->blksz) > s) 234 { if((r = s - f->size) < 0) 235 r = 0; 236 } 237 /* try to align buffer to block boundary to enhance I/O speed */ 238 else if(f->blksz > 0 && f->size >= 2*f->blksz) 239 r = p - (p%f->blksz); 240 else 241 { r = p; 242 243 /* seeking around and wasting data, be conservative */ 244 if(f->iosz > 0 && (p > f->lpos || p < f->lpos-f->size) ) 245 f->bits |= SF_JUSTSEEK; 246 } 247 248 if((hardseek || r != f->here) && (f->here = SFSK(f,r,SEEK_SET,f->disc)) != r) 249 { if(r < p) /* now try to just get to p */ 250 f->here = SFSK(f,p,SEEK_SET,f->disc); 251 if(f->here != p) 252 p = -1; 253 goto done; 254 } 255 256 if(r < p) /* read to cover p */ 257 { (void)SFRD(f, f->data, f->size, f->disc); 258 if(p <= f->here && p >= (f->here - (f->endb - f->data)) ) 259 f->next = f->endb - (size_t)(f->here-p); 260 else /* recover from read failure by just seeking to p */ 261 { f->next = f->endb = f->data; 262 if((f->here = SFSK(f,p,SEEK_SET,f->disc)) != p) 263 p = -1; 264 } 265 } 266 267 done : 268 if(f->here < 0) /* hasn't been the best of time */ 269 { f->extent = -1; 270 f->here = 0; 271 } 272 273 f->lpos = p; 274 275 SFOPEN(f,local); 276 277 if(mustsync) 278 sfsync(f); 279 SFMTXRETURN(f, p); 280 } 281