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 "sfhdr.h" 23*4887Schin static char* Version = "\n@(#)$Id: sfio (AT&T Research) 2006-02-07 $\0\n"; 24*4887Schin 25*4887Schin /* Functions to set a given stream to some desired mode 26*4887Schin ** 27*4887Schin ** Written by Kiem-Phong Vo. 28*4887Schin ** 29*4887Schin ** Modifications: 30*4887Schin ** 06/27/1990 (first version) 31*4887Schin ** 01/06/1991 32*4887Schin ** 07/08/1991 33*4887Schin ** 06/18/1992 34*4887Schin ** 02/02/1993 35*4887Schin ** 05/25/1993 36*4887Schin ** 02/07/1994 37*4887Schin ** 05/21/1996 38*4887Schin ** 08/01/1997 39*4887Schin ** 08/01/1998 (extended formatting) 40*4887Schin ** 09/09/1999 (thread-safe) 41*4887Schin ** 02/01/2001 (adaptive buffering) 42*4887Schin ** 05/31/2002 (multi-byte handling in sfvprintf/vscanf) 43*4887Schin ** 09/06/2002 (SF_IOINTR flag) 44*4887Schin ** 11/15/2002 (%#c for sfvprintf) 45*4887Schin ** 05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data) 46*4887Schin ** (%I1d is fixed to handle "signed char" correctly) 47*4887Schin ** 01/01/2004 Porting issues to various platforms resolved. 48*4887Schin */ 49*4887Schin 50*4887Schin /* the below is for protecting the application from SIGPIPE */ 51*4887Schin #if _PACKAGE_ast 52*4887Schin #include <sig.h> 53*4887Schin #include <wait.h> 54*4887Schin #define Sfsignal_f Sig_handler_t 55*4887Schin #else 56*4887Schin #include <signal.h> 57*4887Schin typedef void(* Sfsignal_f)_ARG_((int)); 58*4887Schin #endif 59*4887Schin static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */ 60*4887Schin 61*4887Schin /* done at exiting time */ 62*4887Schin #if __STD_C 63*4887Schin static void _sfcleanup(void) 64*4887Schin #else 65*4887Schin static void _sfcleanup() 66*4887Schin #endif 67*4887Schin { 68*4887Schin reg Sfpool_t* p; 69*4887Schin reg Sfio_t* f; 70*4887Schin reg int n; 71*4887Schin reg int pool; 72*4887Schin 73*4887Schin f = (Sfio_t*)Version; /* shut compiler warning */ 74*4887Schin 75*4887Schin /* set this so that no more buffering is allowed for write streams */ 76*4887Schin _Sfexiting = 1001; 77*4887Schin 78*4887Schin sfsync(NIL(Sfio_t*)); 79*4887Schin 80*4887Schin for(p = &_Sfpool; p; p = p->next) 81*4887Schin { for(n = 0; n < p->n_sf; ++n) 82*4887Schin { if(!(f = p->sf[n]) || SFFROZEN(f) ) 83*4887Schin continue; 84*4887Schin 85*4887Schin SFLOCK(f,0); 86*4887Schin SFMTXLOCK(f); 87*4887Schin 88*4887Schin /* let application know that we are leaving */ 89*4887Schin (void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*)); 90*4887Schin 91*4887Schin if(f->flags&SF_STRING) 92*4887Schin continue; 93*4887Schin 94*4887Schin /* from now on, write streams are unbuffered */ 95*4887Schin pool = f->mode&SF_POOL; 96*4887Schin f->mode &= ~SF_POOL; 97*4887Schin if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE)) 98*4887Schin (void)_sfmode(f,SF_WRITE,1); 99*4887Schin if(((f->bits&SF_MMAP) && f->data) || 100*4887Schin ((f->mode&SF_WRITE) && f->next == f->data) ) 101*4887Schin (void)SFSETBUF(f,NIL(Void_t*),0); 102*4887Schin f->mode |= pool; 103*4887Schin 104*4887Schin SFMTXUNLOCK(f); 105*4887Schin SFOPEN(f,0); 106*4887Schin } 107*4887Schin } 108*4887Schin } 109*4887Schin 110*4887Schin /* put into discrete pool */ 111*4887Schin #if __STD_C 112*4887Schin int _sfsetpool(Sfio_t* f) 113*4887Schin #else 114*4887Schin int _sfsetpool(f) 115*4887Schin Sfio_t* f; 116*4887Schin #endif 117*4887Schin { 118*4887Schin reg Sfpool_t* p; 119*4887Schin reg Sfio_t** array; 120*4887Schin reg int n, rv; 121*4887Schin 122*4887Schin if(!_Sfcleanup) 123*4887Schin { _Sfcleanup = _sfcleanup; 124*4887Schin (void)atexit(_sfcleanup); 125*4887Schin } 126*4887Schin 127*4887Schin if(!(p = f->pool) ) 128*4887Schin p = f->pool = &_Sfpool; 129*4887Schin 130*4887Schin POOLMTXSTART(p); 131*4887Schin 132*4887Schin rv = -1; 133*4887Schin 134*4887Schin if(p->n_sf >= p->s_sf) 135*4887Schin { if(p->s_sf == 0) /* initialize pool array */ 136*4887Schin { p->s_sf = sizeof(p->array)/sizeof(p->array[0]); 137*4887Schin p->sf = p->array; 138*4887Schin } 139*4887Schin else /* allocate a larger array */ 140*4887Schin { n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4; 141*4887Schin if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) ) 142*4887Schin goto done; 143*4887Schin 144*4887Schin /* move old array to new one */ 145*4887Schin memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*)); 146*4887Schin if(p->sf != p->array) 147*4887Schin free((Void_t*)p->sf); 148*4887Schin 149*4887Schin p->sf = array; 150*4887Schin p->s_sf = n; 151*4887Schin } 152*4887Schin } 153*4887Schin 154*4887Schin /* always add at end of array because if this was done during some sort 155*4887Schin of walk thru all streams, we'll want the new stream to be seen. 156*4887Schin */ 157*4887Schin p->sf[p->n_sf++] = f; 158*4887Schin rv = 0; 159*4887Schin 160*4887Schin done: 161*4887Schin POOLMTXRETURN(p, rv); 162*4887Schin } 163*4887Schin 164*4887Schin /* create an auxiliary buffer for sfgetr/sfreserve/sfputr */ 165*4887Schin #if __STD_C 166*4887Schin Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size) 167*4887Schin #else 168*4887Schin Sfrsrv_t* _sfrsrv(f,size) 169*4887Schin reg Sfio_t* f; 170*4887Schin reg ssize_t size; 171*4887Schin #endif 172*4887Schin { 173*4887Schin Sfrsrv_t *rsrv, *rs; 174*4887Schin 175*4887Schin /* make buffer if nothing yet */ 176*4887Schin size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN; 177*4887Schin if(!(rsrv = f->rsrv) || size > rsrv->size) 178*4887Schin { if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t)))) 179*4887Schin size = -1; 180*4887Schin else 181*4887Schin { if(rsrv) 182*4887Schin { if(rsrv->slen > 0) 183*4887Schin memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen); 184*4887Schin free(rsrv); 185*4887Schin } 186*4887Schin f->rsrv = rsrv = rs; 187*4887Schin rsrv->size = size; 188*4887Schin rsrv->slen = 0; 189*4887Schin } 190*4887Schin } 191*4887Schin 192*4887Schin if(rsrv && size > 0) 193*4887Schin rsrv->slen = 0; 194*4887Schin 195*4887Schin return size >= 0 ? rsrv : NIL(Sfrsrv_t*); 196*4887Schin } 197*4887Schin 198*4887Schin #ifdef SIGPIPE 199*4887Schin #if __STD_C 200*4887Schin static void ignoresig(int sig) 201*4887Schin #else 202*4887Schin static void ignoresig(sig) 203*4887Schin int sig; 204*4887Schin #endif 205*4887Schin { 206*4887Schin signal(sig, ignoresig); 207*4887Schin } 208*4887Schin #endif 209*4887Schin 210*4887Schin #if __STD_C 211*4887Schin int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio) 212*4887Schin #else 213*4887Schin int _sfpopen(f, fd, pid, stdio) 214*4887Schin reg Sfio_t* f; 215*4887Schin int fd; 216*4887Schin int pid; 217*4887Schin int stdio; /* stdio popen() does not reset SIGPIPE handler */ 218*4887Schin #endif 219*4887Schin { 220*4887Schin reg Sfproc_t* p; 221*4887Schin 222*4887Schin if(f->proc) 223*4887Schin return 0; 224*4887Schin 225*4887Schin if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) ) 226*4887Schin return -1; 227*4887Schin 228*4887Schin p->pid = pid; 229*4887Schin p->size = p->ndata = 0; 230*4887Schin p->rdata = NIL(uchar*); 231*4887Schin p->file = fd; 232*4887Schin p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0; 233*4887Schin 234*4887Schin #ifdef SIGPIPE /* protect from broken pipe signal */ 235*4887Schin if(p->sigp) 236*4887Schin { Sfsignal_f handler; 237*4887Schin 238*4887Schin (void)vtmtxlock(_Sfmutex); 239*4887Schin if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL && 240*4887Schin handler != ignoresig) 241*4887Schin signal(SIGPIPE, handler); /* honor user handler */ 242*4887Schin _Sfsigp += 1; 243*4887Schin (void)vtmtxunlock(_Sfmutex); 244*4887Schin } 245*4887Schin #endif 246*4887Schin 247*4887Schin return 0; 248*4887Schin } 249*4887Schin 250*4887Schin #if __STD_C 251*4887Schin int _sfpclose(reg Sfio_t* f) 252*4887Schin #else 253*4887Schin int _sfpclose(f) 254*4887Schin reg Sfio_t* f; /* stream to close */ 255*4887Schin #endif 256*4887Schin { 257*4887Schin Sfproc_t* p; 258*4887Schin int pid, status; 259*4887Schin 260*4887Schin if(!(p = f->proc)) 261*4887Schin return -1; 262*4887Schin f->proc = NIL(Sfproc_t*); 263*4887Schin 264*4887Schin if(p->rdata) 265*4887Schin free(p->rdata); 266*4887Schin 267*4887Schin if(p->pid < 0) 268*4887Schin status = 0; 269*4887Schin else 270*4887Schin { /* close the associated stream */ 271*4887Schin if(p->file >= 0) 272*4887Schin CLOSE(p->file); 273*4887Schin 274*4887Schin /* wait for process termination */ 275*4887Schin #if _PACKAGE_ast 276*4887Schin sigcritical(SIG_REG_EXEC|SIG_REG_PROC); 277*4887Schin #endif 278*4887Schin while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR) 279*4887Schin ; 280*4887Schin if(pid == -1) 281*4887Schin status = -1; 282*4887Schin #if _PACKAGE_ast 283*4887Schin sigcritical(0); 284*4887Schin #endif 285*4887Schin 286*4887Schin #ifdef SIGPIPE 287*4887Schin (void)vtmtxlock(_Sfmutex); 288*4887Schin if(p->sigp && (_Sfsigp -= 1) <= 0) 289*4887Schin { Sfsignal_f handler; 290*4887Schin if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL && 291*4887Schin handler != ignoresig) 292*4887Schin signal(SIGPIPE,handler); /* honor user handler */ 293*4887Schin _Sfsigp = 0; 294*4887Schin } 295*4887Schin (void)vtmtxunlock(_Sfmutex); 296*4887Schin #endif 297*4887Schin } 298*4887Schin 299*4887Schin free(p); 300*4887Schin return status; 301*4887Schin } 302*4887Schin 303*4887Schin #if __STD_C 304*4887Schin static int _sfpmode(Sfio_t* f, int type) 305*4887Schin #else 306*4887Schin static int _sfpmode(f,type) 307*4887Schin Sfio_t* f; 308*4887Schin int type; 309*4887Schin #endif 310*4887Schin { 311*4887Schin Sfproc_t* p; 312*4887Schin 313*4887Schin if(!(p = f->proc) ) 314*4887Schin return -1; 315*4887Schin 316*4887Schin if(type == SF_WRITE) 317*4887Schin { /* save unread data */ 318*4887Schin p->ndata = f->endb-f->next; 319*4887Schin if(p->ndata > p->size) 320*4887Schin { if(p->rdata) 321*4887Schin free((char*)p->rdata); 322*4887Schin if((p->rdata = (uchar*)malloc(p->ndata)) ) 323*4887Schin p->size = p->ndata; 324*4887Schin else 325*4887Schin { p->size = 0; 326*4887Schin return -1; 327*4887Schin } 328*4887Schin } 329*4887Schin if(p->ndata > 0) 330*4887Schin memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata); 331*4887Schin f->endb = f->data; 332*4887Schin } 333*4887Schin else 334*4887Schin { /* restore read data */ 335*4887Schin if(p->ndata > f->size) /* may lose data!!! */ 336*4887Schin p->ndata = f->size; 337*4887Schin if(p->ndata > 0) 338*4887Schin { memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata); 339*4887Schin f->endb = f->data+p->ndata; 340*4887Schin p->ndata = 0; 341*4887Schin } 342*4887Schin } 343*4887Schin 344*4887Schin /* switch file descriptor */ 345*4887Schin if(p->pid >= 0) 346*4887Schin { type = f->file; 347*4887Schin f->file = p->file; 348*4887Schin p->file = type; 349*4887Schin } 350*4887Schin 351*4887Schin return 0; 352*4887Schin } 353*4887Schin 354*4887Schin #if __STD_C 355*4887Schin int _sfmode(reg Sfio_t* f, reg int wanted, reg int local) 356*4887Schin #else 357*4887Schin int _sfmode(f, wanted, local) 358*4887Schin reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */ 359*4887Schin reg int wanted; /* desired mode */ 360*4887Schin reg int local; /* a local call */ 361*4887Schin #endif 362*4887Schin { 363*4887Schin reg int n; 364*4887Schin Sfoff_t addr; 365*4887Schin reg int rv = 0; 366*4887Schin 367*4887Schin SFONCE(); /* initialize mutexes */ 368*4887Schin 369*4887Schin if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */ 370*4887Schin { wanted &= ~SF_SYNCED; 371*4887Schin if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) ) 372*4887Schin { f->next = f->endb = f->endr = f->data; 373*4887Schin f->mode &= ~SF_SYNCED; 374*4887Schin } 375*4887Schin } 376*4887Schin 377*4887Schin if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0)) 378*4887Schin { if(local || !f->disc || !f->disc->exceptf) 379*4887Schin { local = 1; 380*4887Schin goto err_notify; 381*4887Schin } 382*4887Schin 383*4887Schin for(;;) 384*4887Schin { if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0) 385*4887Schin return rv; 386*4887Schin if((!local && SFFROZEN(f)) || 387*4887Schin (!(f->flags&SF_STRING) && f->file < 0) ) 388*4887Schin { if(rv == 0) 389*4887Schin { local = 1; 390*4887Schin goto err_notify; 391*4887Schin } 392*4887Schin else continue; 393*4887Schin } 394*4887Schin else break; 395*4887Schin } 396*4887Schin } 397*4887Schin 398*4887Schin if(f->mode&SF_GETR) 399*4887Schin { f->mode &= ~SF_GETR; 400*4887Schin #ifdef MAP_TYPE 401*4887Schin if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) ) 402*4887Schin { /* turn off mmap to avoid page faulting */ 403*4887Schin sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 404*4887Schin f->tiny[0] = 0; 405*4887Schin } 406*4887Schin else 407*4887Schin #endif 408*4887Schin if(f->getr) 409*4887Schin { f->next[-1] = f->getr; 410*4887Schin f->getr = 0; 411*4887Schin } 412*4887Schin } 413*4887Schin 414*4887Schin if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */ 415*4887Schin (*_Sfstdsync)(f); 416*4887Schin 417*4887Schin if(f->disc == _Sfudisc && wanted == SF_WRITE && 418*4887Schin sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 ) 419*4887Schin { local = 1; 420*4887Schin goto err_notify; 421*4887Schin } 422*4887Schin 423*4887Schin if(f->mode&SF_POOL) 424*4887Schin { /* move to head of pool */ 425*4887Schin if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 ) 426*4887Schin { local = 1; 427*4887Schin goto err_notify; 428*4887Schin } 429*4887Schin f->mode &= ~SF_POOL; 430*4887Schin } 431*4887Schin 432*4887Schin SFLOCK(f,local); 433*4887Schin 434*4887Schin /* buffer initialization */ 435*4887Schin wanted &= SF_RDWR; 436*4887Schin if(f->mode&SF_INIT) 437*4887Schin { 438*4887Schin if(!f->pool && _sfsetpool(f) < 0) 439*4887Schin { rv = -1; 440*4887Schin goto done; 441*4887Schin } 442*4887Schin 443*4887Schin if(wanted == 0) 444*4887Schin goto done; 445*4887Schin 446*4887Schin if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) ) 447*4887Schin goto err_notify; 448*4887Schin 449*4887Schin if((f->flags&SF_STRING) && f->size >= 0 && f->data) 450*4887Schin { f->mode &= ~SF_INIT; 451*4887Schin f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ? 452*4887Schin f->size : 0; 453*4887Schin f->here = 0; 454*4887Schin f->endb = f->data + f->size; 455*4887Schin f->next = f->endr = f->endw = f->data; 456*4887Schin if(f->mode&SF_READ) 457*4887Schin f->endr = f->endb; 458*4887Schin else f->endw = f->endb; 459*4887Schin } 460*4887Schin else 461*4887Schin { n = f->flags; 462*4887Schin (void)SFSETBUF(f,f->data,f->size); 463*4887Schin f->flags |= (n&SF_MALLOC); 464*4887Schin } 465*4887Schin } 466*4887Schin 467*4887Schin if(wanted == (int)SFMODE(f,1)) 468*4887Schin goto done; 469*4887Schin 470*4887Schin switch(SFMODE(f,1)) 471*4887Schin { 472*4887Schin case SF_WRITE: /* switching to SF_READ */ 473*4887Schin if(wanted == 0 || wanted == SF_WRITE) 474*4887Schin break; 475*4887Schin if(!(f->flags&SF_READ) ) 476*4887Schin goto err_notify; 477*4887Schin else if(f->flags&SF_STRING) 478*4887Schin { SFSTRSIZE(f); 479*4887Schin f->endb = f->data+f->extent; 480*4887Schin f->mode = SF_READ; 481*4887Schin break; 482*4887Schin } 483*4887Schin 484*4887Schin /* reset buffer */ 485*4887Schin if(f->next > f->data && SFFLSBUF(f,-1) < 0) 486*4887Schin goto err_notify; 487*4887Schin 488*4887Schin if(f->size == 0) 489*4887Schin { /* unbuffered */ 490*4887Schin f->data = f->tiny; 491*4887Schin f->size = sizeof(f->tiny); 492*4887Schin } 493*4887Schin f->next = f->endr = f->endw = f->endb = f->data; 494*4887Schin f->mode = SF_READ|SF_LOCK; 495*4887Schin 496*4887Schin /* restore saved read data for coprocess */ 497*4887Schin if(f->proc && _sfpmode(f,wanted) < 0) 498*4887Schin goto err_notify; 499*4887Schin 500*4887Schin break; 501*4887Schin 502*4887Schin case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */ 503*4887Schin if(wanted != SF_WRITE) 504*4887Schin { /* just reset the pointers */ 505*4887Schin f->mode = SF_READ|SF_LOCK; 506*4887Schin 507*4887Schin /* see if must go with new physical location */ 508*4887Schin if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) && 509*4887Schin (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here) 510*4887Schin { 511*4887Schin #ifdef MAP_TYPE 512*4887Schin if((f->bits&SF_MMAP) && f->data) 513*4887Schin { SFMUNMAP(f,f->data,f->endb-f->data); 514*4887Schin f->data = NIL(uchar*); 515*4887Schin } 516*4887Schin #endif 517*4887Schin f->endb = f->endr = f->endw = f->next = f->data; 518*4887Schin f->here = addr; 519*4887Schin } 520*4887Schin else 521*4887Schin { addr = f->here + (f->endb - f->next); 522*4887Schin if(SFSK(f,addr,SEEK_SET,f->disc) < 0) 523*4887Schin goto err_notify; 524*4887Schin f->here = addr; 525*4887Schin } 526*4887Schin 527*4887Schin break; 528*4887Schin } 529*4887Schin /* fall thru */ 530*4887Schin 531*4887Schin case SF_READ: /* switching to SF_WRITE */ 532*4887Schin if(wanted != SF_WRITE) 533*4887Schin break; 534*4887Schin else if(!(f->flags&SF_WRITE)) 535*4887Schin goto err_notify; 536*4887Schin else if(f->flags&SF_STRING) 537*4887Schin { f->endb = f->data+f->size; 538*4887Schin f->mode = SF_WRITE|SF_LOCK; 539*4887Schin break; 540*4887Schin } 541*4887Schin 542*4887Schin /* save unread data before switching mode */ 543*4887Schin if(f->proc && _sfpmode(f,wanted) < 0) 544*4887Schin goto err_notify; 545*4887Schin 546*4887Schin /* reset buffer and seek pointer */ 547*4887Schin if(!(f->mode&SF_SYNCED) ) 548*4887Schin { n = f->endb - f->next; 549*4887Schin if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) ) 550*4887Schin { /* reset file pointer */ 551*4887Schin addr = f->here - n; 552*4887Schin if(SFSK(f,addr,SEEK_SET,f->disc) < 0) 553*4887Schin goto err_notify; 554*4887Schin f->here = addr; 555*4887Schin } 556*4887Schin } 557*4887Schin 558*4887Schin f->mode = SF_WRITE|SF_LOCK; 559*4887Schin #ifdef MAP_TYPE 560*4887Schin if(f->bits&SF_MMAP) 561*4887Schin { if(f->data) 562*4887Schin SFMUNMAP(f,f->data,f->endb-f->data); 563*4887Schin (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND); 564*4887Schin } 565*4887Schin #endif 566*4887Schin if(f->data == f->tiny) 567*4887Schin { f->endb = f->data = f->next = NIL(uchar*); 568*4887Schin f->size = 0; 569*4887Schin } 570*4887Schin else f->endb = (f->next = f->data) + f->size; 571*4887Schin 572*4887Schin break; 573*4887Schin 574*4887Schin default: /* unknown case */ 575*4887Schin err_notify: 576*4887Schin if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR) 577*4887Schin wanted = SF_READ; 578*4887Schin 579*4887Schin /* set errno for operations that access wrong stream type */ 580*4887Schin if(wanted != (f->mode&SF_RDWR) && f->file >= 0) 581*4887Schin errno = EBADF; 582*4887Schin 583*4887Schin if(_Sfnotify) /* notify application of the error */ 584*4887Schin (*_Sfnotify)(f,wanted,f->file); 585*4887Schin 586*4887Schin rv = -1; 587*4887Schin break; 588*4887Schin } 589*4887Schin 590*4887Schin done: 591*4887Schin SFOPEN(f,local); 592*4887Schin return rv; 593*4887Schin } 594