Logo Search packages:      
Sourcecode: 9base version File versions  Download package

archive.c

#include    "mk.h"
#define     ARMAG "!<arch>\n"
#define     SARMAG      8

#define     ARFMAG      "`\n"
#define SARNAME   16

struct      ar_hdr
{
      char  name[SARNAME];
      char  date[12];
      char  uid[6];
      char  gid[6];
      char  mode[8];
      char  size[10];
      char  fmag[2];
};
#define     SAR_HDR     (SARNAME+44)

static int dolong = 1;

static void atimes(char *);
static char *split(char*, char**);

long
readn(int f, void *av, long n)
{
      char *a;
      long m, t;

      a = av;
      t = 0;
      while(t < n){
            m = read(f, a+t, n-t);
            if(m <= 0){
                  if(t == 0)
                        return m;
                  break;
            }
            t += m;
      }
      return t;
}
long
atimeof(int force, char *name)
{
      Symtab *sym;
      long t;
      char *archive, *member, buf[512];

      archive = split(name, &member);
      if(archive == 0)
            Exit();

      t = mtime(archive);
      sym = symlook(archive, S_AGG, 0);
      if(sym){
            if(force || (t > (long)sym->value)){
                  atimes(archive);
                  sym->value = (void *)t;
            }
      }
      else{
            atimes(archive);
            /* mark the aggegate as having been done */
            symlook(strdup(archive), S_AGG, "")->value = (void *)t;
      }
            /* truncate long member name to sizeof of name field in archive header */
      if(dolong)
            snprint(buf, sizeof(buf), "%s(%s)", archive, member);
      else
            snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
      sym = symlook(buf, S_TIME, 0);
      if (sym)
            return (long)sym->value;      /* uggh */
      return 0;
}

void
atouch(char *name)
{
      char *archive, *member;
      int fd, i;
      struct ar_hdr h;
      long t;

      archive = split(name, &member);
      if(archive == 0)
            Exit();

      fd = open(archive, ORDWR);
      if(fd < 0){
            fd = create(archive, OWRITE, 0666);
            if(fd < 0){
                  fprint(2, "create %s: %r\n", archive);
                  Exit();
            }
            write(fd, ARMAG, SARMAG);
      }
      if(symlook(name, S_TIME, 0)){
            /* hoon off and change it in situ */
            LSEEK(fd, SARMAG, 0);
            while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
                  for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
                              ;
                  h.name[i+1]=0;
                  if(strcmp(member, h.name) == 0){
                        t = SARNAME-sizeof(h);  /* ughgghh */
                        LSEEK(fd, t, 1);
                        fprint(fd, "%-12ld", time(0));
                        break;
                  }
                  t = atol(h.size);
                  if(t&01) t++;
                  LSEEK(fd, t, 1);
            }
      }
      close(fd);
}

static void
atimes(char *ar)
{
      struct ar_hdr h;
      long t;
      int fd, i, namelen;
      char buf[2048], *p, *strings;
      char name[1024];
      Symtab *sym;

      strings = nil;
      fd = open(ar, OREAD);
      if(fd < 0)
            return;

      if(read(fd, buf, SARMAG) != SARMAG){
            close(fd);
            return;
      }
      while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
            t = atol(h.date);
            if(t == 0)  /* as it sometimes happens; thanks ken */
                  t = 1;
            namelen = 0;
            if(memcmp(h.name, "#1/", 3) == 0){  /* BSD */
                  namelen = atoi(h.name+3);
                  if(namelen >= sizeof name){
                        namelen = 0;
                        goto skip;
                  }
                  if(readn(fd, name, namelen) != namelen)
                        break;
                  name[namelen] = 0;
            }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
                  /* date, uid, gid, mode all ' ' */
                  for(i=2; i<16+12+6+6+8; i++)
                        if(h.name[i] != ' ')
                              goto skip;
                  t = atol(h.size);
                  if(t&01)
                        t++;
                  free(strings);
                  strings = malloc(t+1);
                  if(strings){
                        if(readn(fd, strings, t) != t){
                              free(strings);
                              strings = nil;
                              break;
                        }
                        strings[t] = 0;
                        continue;
                  }
                  goto skip;
            }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){
                  i = strtol(h.name+1, &p, 10);
                  if(*p != ' ' || i >= strlen(strings))
                        goto skip;
                  p = strings+i;
                  for(; *p && *p != '/'; p++)
                        ;
                  namelen = p-(strings+i);
                  if(namelen >= sizeof name){
                        namelen = 0;
                        goto skip;
                  }
                  memmove(name, strings+i, namelen);
                  name[namelen] = 0;
                  namelen = 0;
            }else{
                  strncpy(name, h.name, sizeof(h.name));
                  for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
                              ;
                  if(name[i] == '/')            /* system V bug */
                        i--;
                  name[i+1]=0;
            }
            snprint(buf, sizeof buf, "%s(%s)", ar, name);
            sym = symlook(strdup(buf), S_TIME, (void *)t);
            sym->value = (void *)t;
      skip:
            t = atol(h.size);
            if(t&01) t++;
            t -= namelen;
            LSEEK(fd, t, 1);
      }
      close(fd);
      free(strings);
}

static int
type(char *file)
{
      int fd;
      char buf[SARMAG];

      fd = open(file, OREAD);
      if(fd < 0){
            if(symlook(file, S_BITCH, 0) == 0){
                  if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0)
                        Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
                  symlook(file, S_BITCH, (void *)file);
            }
            return 1;
      }
      if(read(fd, buf, SARMAG) != SARMAG){
            close(fd);
            return 0;
      }
      close(fd);
      return !strncmp(ARMAG, buf, SARMAG);
}

static char*
split(char *name, char **member)
{
      char *p, *q;

      p = strdup(name);
      q = utfrune(p, '(');
      if(q){
            *q++ = 0;
            if(member)
                  *member = q;
            q = utfrune(q, ')');
            if (q)
                  *q = 0;
            if(type(p))
                  return p;
            free(p);
            fprint(2, "mk: '%s' is not an archive\n", name);
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index