Logo Search packages:      
Sourcecode: ksh version File versions  Download package

sfmode.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2008 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#include    "sfhdr.h"
static char*      Version = "\n@(#)$Id: sfio (AT&T Research) 2006-02-07 $\0\n";

/*    Functions to set a given stream to some desired mode
**
**    Written by Kiem-Phong Vo.
**
**    Modifications:
**          06/27/1990 (first version)
**          01/06/1991
**          07/08/1991
**          06/18/1992
**          02/02/1993
**          05/25/1993
**          02/07/1994
**          05/21/1996
**          08/01/1997
**          08/01/1998 (extended formatting)
**          09/09/1999 (thread-safe)
**          02/01/2001 (adaptive buffering)
**          05/31/2002 (multi-byte handling in sfvprintf/vscanf)
**          09/06/2002 (SF_IOINTR flag)
**          11/15/2002 (%#c for sfvprintf)
**          05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data)
**                   (%I1d is fixed to handle "signed char" correctly)
**          01/01/2004 Porting issues to various platforms resolved.
*/

/* the below is for protecting the application from SIGPIPE */
#if _PACKAGE_ast
#include          <sig.h>
#include          <wait.h>
#define Sfsignal_f      Sig_handler_t
#else
#include          <signal.h>
typedef void(*          Sfsignal_f)_ARG_((int));
#endif
static int        _Sfsigp = 0; /* # of streams needing SIGPIPE protection */ 

/* done at exiting time */
#if __STD_C
static void _sfcleanup(void)
#else
static void _sfcleanup()
#endif
{
      reg Sfpool_t*     p;
      reg Sfio_t* f;
      reg int           n;
      reg int           pool;

      f = (Sfio_t*)Version; /* shut compiler warning */

      /* set this so that no more buffering is allowed for write streams */
      _Sfexiting = 1001;

      sfsync(NIL(Sfio_t*));

      for(p = &_Sfpool; p; p = p->next)
      {     for(n = 0; n < p->n_sf; ++n)
            {     if(!(f = p->sf[n]) || SFFROZEN(f) )
                        continue;

                  SFLOCK(f,0);
                  SFMTXLOCK(f);

                  /* let application know that we are leaving */
                  (void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*));

                  if(f->flags&SF_STRING)
                        continue;

                  /* from now on, write streams are unbuffered */
                  pool = f->mode&SF_POOL;
                  f->mode &= ~SF_POOL;
                  if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
                        (void)_sfmode(f,SF_WRITE,1);
                  if(((f->bits&SF_MMAP) && f->data) ||
                     ((f->mode&SF_WRITE) && f->next == f->data) )
                        (void)SFSETBUF(f,NIL(Void_t*),0);
                  f->mode |= pool;

                  SFMTXUNLOCK(f);
                  SFOPEN(f,0);
            }
      }
}

/* put into discrete pool */
#if __STD_C
int _sfsetpool(Sfio_t* f)
#else
int _sfsetpool(f)
Sfio_t*     f;
#endif
{
      reg Sfpool_t*     p;
      reg Sfio_t**      array;
      reg int           n, rv;

      if(!_Sfcleanup)
      {     _Sfcleanup = _sfcleanup;
            (void)atexit(_sfcleanup);
      }

      if(!(p = f->pool) )
            p = f->pool = &_Sfpool;

      POOLMTXSTART(p);

      rv = -1;

      if(p->n_sf >= p->s_sf)
      {     if(p->s_sf == 0) /* initialize pool array */
            {     p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
                  p->sf = p->array;
            }
            else  /* allocate a larger array */
            {     n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
                  if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
                        goto done;

                  /* move old array to new one */
                  memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
                  if(p->sf != p->array)
                        free((Void_t*)p->sf);

                  p->sf = array;
                  p->s_sf = n;
            }
      }

      /* always add at end of array because if this was done during some sort
         of walk thru all streams, we'll want the new stream to be seen.
      */
      p->sf[p->n_sf++] = f;
      rv = 0;

done:
      POOLMTXRETURN(p, rv);
}

/* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
#if __STD_C
Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
#else
Sfrsrv_t* _sfrsrv(f,size)
reg Sfio_t* f;
reg ssize_t size;
#endif
{
      Sfrsrv_t    *rsrv, *rs;

      /* make buffer if nothing yet */
      size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
      if(!(rsrv = f->rsrv) || size > rsrv->size)
      {     if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
                  size = -1;
            else
            {     if(rsrv)
                  {     if(rsrv->slen > 0)
                              memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
                        free(rsrv);
                  }
                  f->rsrv = rsrv = rs;
                  rsrv->size = size;
                  rsrv->slen = 0;
            }
      }

      if(rsrv && size > 0)
            rsrv->slen = 0;

      return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
}

#ifdef SIGPIPE
#if __STD_C
static void ignoresig(int sig)
#else
static void ignoresig(sig)
int sig;
#endif
{
      signal(sig, ignoresig);
}
#endif

#if __STD_C
int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
#else
int _sfpopen(f, fd, pid, stdio)
reg Sfio_t* f;
int         fd;
int         pid;
int         stdio;      /* stdio popen() does not reset SIGPIPE handler */
#endif
{
      reg Sfproc_t*     p;

      if(f->proc)
            return 0;

      if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
            return -1;

      p->pid = pid;
      p->size = p->ndata = 0;
      p->rdata = NIL(uchar*);
      p->file = fd;
      p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;

#ifdef SIGPIPE    /* protect from broken pipe signal */
      if(p->sigp)
      {     Sfsignal_f  handler;

            (void)vtmtxlock(_Sfmutex);
            if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
                handler != ignoresig)
                  signal(SIGPIPE, handler); /* honor user handler */
            _Sfsigp += 1;
            (void)vtmtxunlock(_Sfmutex);
      }
#endif

      return 0;
}

#if __STD_C
int _sfpclose(reg Sfio_t* f)
#else
int _sfpclose(f)
reg Sfio_t* f;    /* stream to close */
#endif
{
      Sfproc_t*   p;
      int         pid, status;

      if(!(p = f->proc))
            return -1;
      f->proc = NIL(Sfproc_t*);

      if(p->rdata)
            free(p->rdata);

      if(p->pid < 0)
            status = 0;
      else
      {     /* close the associated stream */
            if(p->file >= 0)
                  CLOSE(p->file);

            /* wait for process termination */
#if _PACKAGE_ast
            sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
#endif
            while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
                  ;
            if(pid == -1)
                  status = -1;
#if _PACKAGE_ast
            sigcritical(0);
#endif

#ifdef SIGPIPE
            (void)vtmtxlock(_Sfmutex);
            if(p->sigp && (_Sfsigp -= 1) <= 0)
            {     Sfsignal_f  handler;
                  if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
                     handler != ignoresig)
                        signal(SIGPIPE,handler); /* honor user handler */
                  _Sfsigp = 0;
            }
            (void)vtmtxunlock(_Sfmutex);
#endif
      }

      free(p);
      return status;
}

#if __STD_C
static int _sfpmode(Sfio_t* f, int type)
#else
static int _sfpmode(f,type)
Sfio_t*     f;
int   type;
#endif
{
      Sfproc_t*   p;

      if(!(p = f->proc) )
            return -1;

      if(type == SF_WRITE)
      {     /* save unread data */
            p->ndata = f->endb-f->next;
            if(p->ndata > p->size)
            {     if(p->rdata)
                        free((char*)p->rdata);
                  if((p->rdata = (uchar*)malloc(p->ndata)) )
                        p->size = p->ndata;
                  else
                  {     p->size = 0;
                        return -1;
                  }
            }
            if(p->ndata > 0)
                  memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
            f->endb = f->data;
      }
      else
      {     /* restore read data */
            if(p->ndata > f->size)  /* may lose data!!! */
                  p->ndata = f->size;
            if(p->ndata > 0)
            {     memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
                  f->endb = f->data+p->ndata;
                  p->ndata = 0;
            }
      }

      /* switch file descriptor */
      if(p->pid >= 0)
      {     type = f->file;
            f->file = p->file;
            p->file = type;
      }

      return 0;
}

#if __STD_C
int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
#else
int _sfmode(f, wanted, local)
reg Sfio_t* f;    /* change r/w mode and sync file pointer for this stream */
reg int           wanted;     /* desired mode */
reg int           local;      /* a local call */
#endif
{
      reg int     n;
      Sfoff_t     addr;
      reg int     rv = 0;

      SFONCE();   /* initialize mutexes */

      if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
      {     wanted &= ~SF_SYNCED;
            if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
            {     f->next = f->endb = f->endr = f->data;
                  f->mode &= ~SF_SYNCED;
            }
      }

      if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
      {     if(local || !f->disc || !f->disc->exceptf)
            {     local = 1;
                  goto err_notify;
            }

            for(;;)
            {     if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
                        return rv;
                  if((!local && SFFROZEN(f)) ||
                     (!(f->flags&SF_STRING) && f->file < 0) )
                  {     if(rv == 0)
                        {     local = 1;
                              goto err_notify;
                        }
                        else  continue;
                  }
                  else  break;
            }
      }

      if(f->mode&SF_GETR)
      {     f->mode &= ~SF_GETR;
#ifdef MAP_TYPE
            if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
            {     /* turn off mmap to avoid page faulting */
                  sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
                  f->tiny[0] = 0;
            }
            else
#endif
            if(f->getr)
            {     f->next[-1] = f->getr;
                  f->getr = 0;
            }
      }

      if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
            (*_Sfstdsync)(f);

      if(f->disc == _Sfudisc && wanted == SF_WRITE &&
         sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
      {     local = 1;
            goto err_notify;
      }

      if(f->mode&SF_POOL)
      {     /* move to head of pool */
            if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
            {     local = 1;
                  goto err_notify;
            }
            f->mode &= ~SF_POOL;
      }

      SFLOCK(f,local);

      /* buffer initialization */
      wanted &= SF_RDWR;
      if(f->mode&SF_INIT)
      {     
            if(!f->pool && _sfsetpool(f) < 0)
            {     rv = -1;
                  goto done;
            }

            if(wanted == 0)
                  goto done;

            if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
                  goto err_notify;

            if((f->flags&SF_STRING) && f->size >= 0 && f->data)
            {     f->mode &= ~SF_INIT;
                  f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
                              f->size : 0;
                  f->here = 0;
                  f->endb = f->data + f->size;
                  f->next = f->endr = f->endw = f->data;
                  if(f->mode&SF_READ)
                        f->endr = f->endb;
                  else  f->endw = f->endb;
            }
            else
            {     n = f->flags;
                  (void)SFSETBUF(f,f->data,f->size);
                  f->flags |= (n&SF_MALLOC);
            }
      }

      if(wanted == (int)SFMODE(f,1))
            goto done;

      switch(SFMODE(f,1))
      {
      case SF_WRITE: /* switching to SF_READ */
            if(wanted == 0 || wanted == SF_WRITE)
                  break;
            if(!(f->flags&SF_READ) )
                  goto err_notify;
            else if(f->flags&SF_STRING)
            {     SFSTRSIZE(f);
                  f->endb = f->data+f->extent;
                  f->mode = SF_READ;
                  break;
            }

            /* reset buffer */
            if(f->next > f->data && SFFLSBUF(f,-1) < 0)
                  goto err_notify;

            if(f->size == 0)
            {     /* unbuffered */
                  f->data = f->tiny;
                  f->size = sizeof(f->tiny);
            }
            f->next = f->endr = f->endw = f->endb = f->data;
            f->mode = SF_READ|SF_LOCK;

            /* restore saved read data for coprocess */
            if(f->proc && _sfpmode(f,wanted) < 0)
                  goto err_notify;

            break;

      case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
            if(wanted != SF_WRITE)
            {     /* just reset the pointers */
                  f->mode = SF_READ|SF_LOCK;

                  /* see if must go with new physical location */
                  if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
                     (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
                  {
#ifdef MAP_TYPE
                        if((f->bits&SF_MMAP) && f->data)
                        {     SFMUNMAP(f,f->data,f->endb-f->data);
                              f->data = NIL(uchar*);
                        }
#endif
                        f->endb = f->endr = f->endw = f->next = f->data;
                        f->here = addr;
                  }
                  else
                  {     addr = f->here + (f->endb - f->next);
                        if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
                              goto err_notify;
                        f->here = addr;
                  }

                  break;
            }
            /* fall thru */

      case SF_READ: /* switching to SF_WRITE */
            if(wanted != SF_WRITE)
                  break;
            else if(!(f->flags&SF_WRITE))
                  goto err_notify;
            else if(f->flags&SF_STRING)
            {     f->endb = f->data+f->size;
                  f->mode = SF_WRITE|SF_LOCK;
                  break;
            }

            /* save unread data before switching mode */
            if(f->proc && _sfpmode(f,wanted) < 0)
                  goto err_notify;

            /* reset buffer and seek pointer */
            if(!(f->mode&SF_SYNCED) )
            {     n = f->endb - f->next;
                  if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
                  {     /* reset file pointer */
                        addr = f->here - n;
                        if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
                              goto err_notify;
                        f->here = addr;
                  }
            }

            f->mode = SF_WRITE|SF_LOCK;
#ifdef MAP_TYPE
            if(f->bits&SF_MMAP)
            {     if(f->data)
                        SFMUNMAP(f,f->data,f->endb-f->data);
                  (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
            }
#endif
            if(f->data == f->tiny)
            {     f->endb = f->data = f->next = NIL(uchar*);
                  f->size = 0;
            }
            else  f->endb = (f->next = f->data) + f->size;

            break;

      default: /* unknown case */
      err_notify:
            if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
                  wanted = SF_READ;

            /* set errno for operations that access wrong stream type */
            if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
                  errno = EBADF;

            if(_Sfnotify) /* notify application of the error */
                  (*_Sfnotify)(f,wanted,f->file);

            rv = -1;
            break;
      }

done:
      SFOPEN(f,local);
      return rv;
}

Generated by  Doxygen 1.6.0   Back to index