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

ar-omf.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 2002-2007 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>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * omf archive format method
 */

#include <ardirlib.h>
#include <cdt.h>
#include <omf.h>

#ifndef EILSEQ
#define EILSEQ          EINVAL
#endif

#define FILENAME    "U_w_i_n"

typedef struct _arfile_
{
      Ardirent_t  st;
      char        *alias;
      Dtlink_t    link;
      int         flags;
      size_t            toffset;
      char        suffix[4];
} Arfile_t;

typedef struct State_s              /* method state               */
{
        Dt_t            *dict;
      void        *addr;
      Arfile_t    lib;
      Arfile_t    *next;
      int         state;
} State_t;

struct Table
{
      struct Table *next;
      size_t      offset;
      size_t      disp;
};

static int namcomp(Dt_t *dp, Void_t *left, Void_t *right, Dtdisc_t *dsp)
{
      char *l= (char*)left;
      char *r= (char*)right;
      char *suffix;
      if(suffix=strrchr(l,'.'))
            return(memcmp(l,r,suffix+1-l));
      return(strcmp(l,r));
}

static int offcomp(Dt_t *dp, Void_t *left, Void_t *right, Dtdisc_t *dsp)
{
      off_t l= *((off_t*)left);
      off_t r= *((off_t*)right);
      if (l < r)
            return -1;
      if (l > r)
            return 1;
      return 0;
}

static Dtdisc_t namdisc =
{
      offsetof(Arfile_t,st.name),-1, offsetof(Arfile_t,link), 0, 0, namcomp
};

static Dtdisc_t offdisc =
{
      offsetof(Arfile_t,st.offset), sizeof(off_t), offsetof(Arfile_t,link), 0, 0, offcomp
};

static unsigned char *readint(unsigned char *cp,int *i, int big)
{
      if(big)
      {
            *i = (*cp) | (cp[1]<<8) | (cp[2]<<16) | (cp[3]<<24);
            return(cp+4);
      }
      *i = (*cp) | (cp[1]<<8);
      return(cp+2);
}

static unsigned char *readindex(unsigned char *cp, int *size)
{
      if(*cp&0x80)
      {
            *size = (*cp&0xf7)<<8 | cp[1];
            return(cp+2);
      }
      *size = *cp++;
      return(cp);
}

#define round(a,b)      (((a)+(b)-1) &~ ((b)-1))

static unsigned int is_omf(int fd)
{
      unsigned char buff[4];
      if(read(fd,buff,4) != 4)
            return(0);
      if(*buff==OMF_THEADR)
            return(buff[3]);
      lseek(fd,(off_t)-4,SEEK_CUR);
      errno =  EILSEQ;
      return(0);
}

static Arfile_t *ar_getnode(Ardir_t *ar, const char *name)
{
      const char *cp;
      Arfile_t *fp;
      Dt_t *dp = ((State_t*)ar->data)->dict;
      if(cp = strrchr(name,'/'))
            name = cp+1;
      fp = (Arfile_t*)dtmatch(dp,(void*)name);
      if(!fp)
      {
            size_t len = strlen(name)+5;
            if(!(fp = newof(0,Arfile_t,1,len)))
                  return(0);
            fp->st.name = (char*)(fp+1);
            memcpy((char*)fp->st.name,name,len);
            if(!strrchr(fp->st.name,'.'))
            {
                  fp->st.name[len-5] = '.';
                  fp->st.name[len-4] = 0;
            }
            fp->suffix[0] = 'o';
            fp->suffix[1] = 0;
            fp->st.mtime = ar->st.st_mtime;
            fp->st.mode = ar->st.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO);
            fp->st.uid = ar->st.st_uid;
            fp->st.gid = ar->st.st_gid;
            dtinsert(dp,fp);
      }
      return(fp);
}

/*
 * closef
 */

static int
omfclose(Ardir_t* ar)
{
      State_t     *sp = (State_t*)ar->data;
      Dt_t  *dp = sp?sp->dict:0;
      if(sp && dp && sp->state)
      {
            /* update modification times */
            Arfile_t *fp;
            for(fp=(Arfile_t*)dtfirst(dp); fp; fp = (Arfile_t*)dtnext(dp,fp))
            {
                  if(fp->flags && fp->toffset>0 && lseek(ar->fd,(off_t)fp->toffset,SEEK_SET)>0)
                  {
                        write(ar->fd,(void*)&fp->st.mtime,sizeof(time_t));
                  }
            }
      }
      if (sp && sp->addr)
            free(sp->addr);
      if (dp)
            dtclose(dp);
      if(sp)
            free(sp);
      return 0;
}

static size_t displacement(struct Table *tp,size_t addr)
{
      size_t disp = 0;
      while(tp)
      {
            disp = tp->disp;
            if(addr>tp->offset)
                  break;
            tp = tp->next;
      }
      return(disp);
}

static void omfload(Ardir_t *ar,unsigned char *base, unsigned char *last, struct Table *tp, int dmars)
{
      State_t *sp = (State_t*)ar->data;
      unsigned char *cp=base, *end=last;
      int *ip;
      Arfile_t *fp;
      int len;
      struct Table *tpnext;
      if(dmars)
      {
            /* string table at the top */
            while(*cp)
                  cp += strlen((char*)cp)+1;
            while(cp[4]==0)
                  cp++;
      }
      else
      {
            readint(cp,&len,1);
            end = base + len;
      }
      for(ip=(int*)cp; (unsigned char*)(ip+6) < end; ip+=7)
      {
            if(dmars)
                  len = *ip;
            else
                  readint((unsigned char*)ip,&len,1);
            if(base+len >= last)
                  break;
            if(!(fp = ar_getnode(ar,(char*)base+len)))
                  return;
            fp->st.mtime = (time_t)ip[1];
            fp->st.mode = (mode_t)ip[2];
            fp->st.uid = (uid_t)ip[3];
            fp->st.gid = (gid_t)ip[4];
            memcpy(fp->suffix,&ip[5],sizeof(fp->suffix));
            fp->toffset = ((char*)&ip[1])-(char*)(sp->addr); 
            fp->toffset += displacement(tp,((unsigned char*)&ip[1])-base);
            if(ip[6])
                  fp->alias = (char*)base+ip[6];
                  
      }
      while(tp)
      {
            tpnext = tp->next;
            free((void*)tp);
            tp = tpnext;
      }
}
/*
 * openf
 */

static int
omfopen(Ardir_t* ar, char* buf, size_t size)
{
      State_t*    state;
      int pagesize;
      unsigned char *addr, *addrstart, *addrmax, *begin,*cp, *base=0, *last;
      char name[PATH_MAX];
      Arfile_t *fp;
      struct Table *tp=0, *tpnew;
      int dmars=0,n,type,special=0,len,flen=strlen(FILENAME ".");

      if (ar->fd>=0 && (size<=0 || *((unsigned char*)buf) != OMF_LIBHDR))
            return -1;
      if(!(state = newof(0,State_t,1,0)))
            return -1;
      ar->data = (void*)state;
      if(!(state->dict = dtopen(&namdisc,Dtoset)))
            goto nope;
      if(ar->fd<0)
            return 0;
      size = (size_t)ar->st.st_size;
      if(!(addr = (unsigned char*)malloc(size)))
            goto nope;
      addrstart = addr;
      state->addr = (void*)addr;
      if(lseek(ar->fd,(off_t)0, SEEK_SET)<0)
            goto nope;
      if(read(ar->fd,(void*)addr,size) < 0)
            goto nope;
      addrmax=addr+size;
      addr = readint(addr+1,&n,0);
      pagesize = n+3;
      while((addr+=n) < addrmax)
      {
            if(*addr==OMF_LIBDHD)
                  return(0);
            cp = addr;
            type = *addr;
            addr = readint(addr+1,&n,0);
            if((type&~1)==OMF_MODEND)
            {
                  if(special)
                  {
                        if(base)
                              omfload(ar,base,last,tp,dmars);
                        special = 0;
                  }
                  else
                  {
                        if(!(fp = ar_getnode(ar,name)))
                              return(0);
                        fp->st.offset = begin-addrstart;
                        fp->st.size = addr+n-begin;
                  }
                  addr +=n;
                  addr = addrstart + round(addr-addrstart,pagesize);
                  n = 0;
            }
            else if(type==OMF_THEADR)
            {
                  if(memcmp(addr+1,FILENAME".",flen))
                  {
                        begin = addr+1;
                        len = *addr;
                        if(addr[1]=='.' && addr[2]=='\\')
                        {
                              len -=2;
                              begin +=2;
                        }
                        memcpy(name,begin,len);
                        name[len] =  0;
                        begin = cp;
                  }
                  else
                        special = 1;
            }
            else if((type&~1)==OMF_LEDATA && special)
            {
                  int offset;
                  cp = readindex(addr,&len);
                  cp= readint(cp,&offset,type&1);
                  dmars = (type&1);
                  len = (n-1) - (cp-addr);
                  if(!(tpnew = newof(0,struct Table,1,0)))
                        return(0);
                  tpnew->next = tp;
                  tp = tpnew;
                  if(!base)
                        base = last = cp;
                  else
                  {
                        tp->disp = cp - (base+offset);
                        memcpy(base+offset,cp,len);
                  }
                  tp->offset = offset;
                  last += len;
            }
      }
 nope:
      omfclose(ar);
      return -1;
}

/*
 * nextf
 */

static Ardirent_t*
omfnext(Ardir_t* ar)
{
      State_t *ap = (State_t*)ar->data;
      Arfile_t *fp;
      if(ap->next)
            ap->next = (Arfile_t*)dtnext(ap->dict,ap->next);
      else
      {
            dtdisc(ap->dict, &offdisc, 0);
            ap->next = (Arfile_t*)dtfirst(ap->dict);
      }
      if(!(fp = ap->next))
            return(0);
      if(*fp->suffix)
      {
            char *last = strrchr(fp->st.name,'.');
            if(last)
                  last++;
            else
                  last = fp->st.name+strlen(fp->st.name);
            memcpy((void*)last,(void*)fp->suffix,sizeof(fp->suffix));
      }
      if(!(ar->flags&ARDIR_FORCE) && fp->alias)
            fp->st.name = fp->alias;
      return(&fp->st);
}


/*
 * returns -1 for error
 * returns 0 for ignore
 * returns ARDIR_CREATE add
 * returns ARDIR_REPLACE replace
 * returns ARDIR_DELETE delete
 */
int omfinsert(Ardir_t *ar, const char *name, int op)
{
      char *suffix,fname[256];
      Dt_t *dp = ((State_t*)ar->data)->dict;
      int m,n,fd;
      Arfile_t *fp;
      struct stat statb;
      int ret = -1;
      if(suffix=strrchr(name,'.'))
            n = (const char*)++suffix - name;
      else
            n = strlen(name);
      if((fd=open(name,O_RDONLY))>=0)
      {
            if(fstat(fd,&statb)>=0 && (m=is_omf(fd)))
            {
                  read(fd,(void*)fname,m);
                  fname[m] = 0;
                  m = memcmp((void*)fname,(void*)name,n);
                  ret = ARDIR_CREATE;
            }
            close(fd);
      }
      fp = (Arfile_t*)dtmatch(dp,(void*)fname);
      if(ret<0 && !((op&ARDIR_DELETE) && fp))
            return -1;
      if(fp)
      {
            if(op&ARDIR_DELETE)
            {
                  dtdelete(dp,(Void_t*)fp);
                  return ARDIR_DELETE;
            }
            if(fp->st.mtime>= statb.st_mtime && (op&ARDIR_NEWER))
                  return 0 ;
            ret = ARDIR_REPLACE;
      }
      else
      {
            if(op&ARDIR_DELETE)
                  return -1 ;
            if(!(fp = (Arfile_t*)ar_getnode(ar,fname)))
                  return -1 ;
      }
      fp->st.mode = statb.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO);
      fp->st.uid = statb.st_uid;
      fp->st.gid = statb.st_gid;
      fp->st.mtime = statb.st_mtime;
      fp->st.size = (size_t)statb.st_size;
      fp->st.offset = ++ar->st.st_size;
      if(m)
            fp->alias = (char*)name;
      if(suffix)
            memcpy(fp->suffix,suffix,sizeof(fp->suffix));
      return(ret);
}

const char *omfspecial(Ardir_t *ar)
{
      return(FILENAME ".o");
}

/*
 * changef
 */

static int
omfchange(Ardir_t* ar, Ardirent_t* ent)
{
      State_t *sp = (State_t*)ar->data;
      Arfile_t *fp = (Arfile_t*)ent;
      fp->flags = 1;
      sp->state = 1;
      return 0;
}

Ardirmeth_t ar_omf =
{
      "omf",
      "omf archive",
      omfopen,
      omfnext,
      omfchange,
      omfinsert,
      omfspecial,
      omfclose,
      ar_omf_next
};

Generated by  Doxygen 1.6.0   Back to index