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