Logo Search packages:      
Sourcecode: ksh version File versions

pax-vdb.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1987-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                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>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped

/*
 * pax vdb format
 */

#include "format.h"

#include <vdb.h>

typedef struct Vdb_s
{
      unsigned char     delimiter;  /* header delimiter           */
      unsigned char     variant;    /* variant header delimiters  */
      Sfio_t*           directory;  /* directory trailer stream   */
      struct stat st;         /* member stat prototype      */
      struct
      {
      char*       base;       /* header buffer base         */
      char*       next;       /* next header                */
      }           header;
} Vdb_t;

static int
vdb_getprologue(Pax_t* pax, Format_t* fp, register Archive_t* ap, File_t* f, unsigned char* buf, size_t size)
{
      register Vdb_t*         vdb = (Vdb_t*)ap->data;
      char*             s;
      char*             t;
      struct stat       st;
      size_t                  i;
      off_t             n;

      if (fstat(ap->io->fd, &st))
            return 0;
      s = state.tmp.buffer;
      n = sizeof(VDB_MAGIC) + sizeof(state.volume) + 1;
      if (size < n)
            return 0;
      s = (char*)buf;
      if (s[0] != VDB_DELIMITER || !strneq(s + 1, VDB_MAGIC, sizeof(VDB_MAGIC) - 1) || s[sizeof(VDB_MAGIC)] != VDB_DELIMITER)
            return 0;
      if (s[sizeof(VDB_MAGIC) + 1] != '\n')
      {
            s[n] = 0;
            if (t = strchr(s, '\n'))
                  *t = 0;
            strncpy(state.volume, s + sizeof(VDB_MAGIC) + 1, sizeof(state.volume) - 2);
      }
      if (lseek(ap->io->fd, (off_t)(-(VDB_LENGTH + 1)), SEEK_END) <= 0)
            return 0;
      if (read(ap->io->fd, s, VDB_LENGTH + 1) != (VDB_LENGTH + 1))
            return 0;
      if (!vdb)
      {
            if (!(vdb = newof(0, Vdb_t, 1, 0)))
                  nospace();
            ap->data = vdb;
      }
      ccmapstr(state.map.a2n, s, VDB_LENGTH + 1);
      vdb->variant = *s++ != '\n';
      if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY) - 1))
            goto nope;
      vdb->delimiter = s[VDB_OFFSET - 1];
      n = strtol(s + VDB_OFFSET, NiL, 10) - sizeof(VDB_DIRECTORY);
      i = lseek(ap->io->fd, (off_t)0, SEEK_CUR) - n - VDB_LENGTH - vdb->variant;
      if (!(vdb->header.base = newof(0, char, i, 1)))
            nospace();
      if (lseek(ap->io->fd, n, SEEK_SET) != n)
            goto nope;
      if (read(ap->io->fd, vdb->header.base, i) != i)
            goto nope;
      ccmapstr(state.map.a2n, vdb->header.base, i);
      *(vdb->header.base + i) = 0;
      if (!strneq(vdb->header.base, VDB_DIRECTORY, sizeof(VDB_DIRECTORY) - 1))
            goto nope;
      if (!(vdb->header.next = strchr(vdb->header.base, '\n')))
            goto nope;
      vdb->header.next++;
      vdb->st.st_mode = modex(vdb->st.st_mode);
      return 1;
 nope:
      free(vdb);
      return 0;
}

static int
vdb_done(Pax_t* pax, register Archive_t* ap)
{
      register Vdb_t*   vdb = (Vdb_t*)ap->data;

      if (vdb)
      {
            if (vdb->directory)
                  sfclose(vdb->directory);
            free(vdb);
            ap->data = 0;
      }
      return 0;
}

static int
vdb_getheader(Pax_t* pax, Archive_t* ap, register File_t* f)
{
      register Vdb_t*   vdb = (Vdb_t*)ap->data;
      char*       s;
      char*       t;
      off_t       n;

      t = vdb->header.next;
      if (!(vdb->header.next = strchr(t, '\n')))
            goto eof;
      *vdb->header.next++ = 0;
      message((-1, "VDB: next=`%s'", t));
      if (vdb->variant)
            vdb->delimiter = *t++;
      f->name = t;
      if (!(t = strchr(t, vdb->delimiter)))
            goto eof;
      *t++ = 0;
      n = strtol(t, &t, 10);
      if (*t++ != vdb->delimiter)
            goto eof;
      if (lseek(ap->io->fd, n, SEEK_SET) != n)
            goto eof;
      *f->st = vdb->st;
      f->st->st_size = strtol(t, &t, 10);
      if (*t++ == vdb->delimiter) do
      {
            if (s = strchr(t, vdb->delimiter))
                  *s++ = 0;
            if (strneq(t, VDB_DATE, sizeof(VDB_DATE) - 1))
                  f->st->st_mtime = strtol(t + sizeof(VDB_DATE), NiL, 10);
            else if (strneq(t, VDB_MODE, sizeof(VDB_MODE) - 1))
                  f->st->st_mode = (strtol(t + sizeof(VDB_MODE), NiL, 8) & X_IPERM) | X_IFREG;
      } while (t = s);
      f->st->st_dev = 0;
      f->st->st_ino = 0;
      f->st->st_nlink = 1;
      IDEVICE(f->st, 0);
      f->linktype = NOLINK;
      f->linkpath = 0;
      f->uidname = 0;
      f->gidname = 0;
      paxsync(pax, ap, 0);
      return 1;
 eof:
      paxsync(pax, ap, 0);
      ap->io->eof = 1;
      ap->io->offset = 0;
      ap->io->count = lseek(ap->io->fd, (off_t)0, SEEK_END);
      return 0;
}

static int
vdb_putprologue(Pax_t* pax, register Archive_t* ap)
{
      register Vdb_t*   vdb = (Vdb_t*)ap->data;

      if (!vdb)
      {
            if (!(vdb = newof(0, Vdb_t, 1, 0)) || !(vdb->directory = sfstropen()))
                  nospace();
            ap->data = vdb;
      }
      sfprintf(vdb->directory, "%c%s%c%s\n", VDB_DELIMITER, VDB_MAGIC, VDB_DELIMITER, state.volume);
      paxwrite(pax, ap, sfstrbase(vdb->directory), sfstrtell(vdb->directory));
      sfstrseek(vdb->directory, 0, SEEK_SET);
      sfprintf(vdb->directory, "%s\n", VDB_DIRECTORY);
      return 1;
}

static int
vdb_putheader(Pax_t* pax, Archive_t* ap, File_t* f)
{
      register Vdb_t*         vdb = (Vdb_t*)ap->data;
      register unsigned char* s;
      register int            c;
      int               n;

      if (state.complete)
            complete(ap, f, state.record.header ? state.record.headerlen : f->namesize);
      if (state.record.header)
            paxwrite(pax, ap, state.record.header, state.record.headerlen);
      else
      {
            f->name[f->namesize - 1] = '\n';
            paxwrite(pax, ap, f->name, f->namesize);
            f->name[f->namesize - 1] = 0;
      }
      if (!(c = state.record.delimiter))
      {
            c = VDB_DELIMITER;
            s = (unsigned char*)state.tmp.buffer;
            n = 1024;
            if (f->fd >= 0)
            {
                  n = read(f->fd, s, n);
                  if (n > 0)
                  {
                        int         dp;
                        int         ds;
                        int         mp = 0;
                        int         ms = 0;
                        unsigned char     hit[UCHAR_MAX + 1];

                        /*
                         * to determine the delimiter, if any
                         */

                        lseek(f->fd, -n, SEEK_CUR);
                        memzero(hit, sizeof(hit));
                        while (--n > 0)
                              hit[*(s + n)]++;
                        for (n = 0; n <= UCHAR_MAX; n++)
                              if (n == '_' || n == '/' || n == '.' || n == '\n' || n == '\\')
                                    /* nop */;
                              else if (isspace(n))
                              {
                                    if ((int)hit[n] > ms)
                                    {
                                          ms = hit[n];
                                          ds = n;
                                    }
                              }
                              else if ((int)hit[n] > mp && isprint(n) && !isalnum(n))
                              {
                                    mp = hit[n];
                                    dp = n;
                              }
                        if (mp)
                              c = dp;
                        else if (ms)
                              c = ds;
                  }
            }
      }
      n = (c == '=') ? ':' : '=';
      sfprintf(vdb->directory, "%c%s%c%I*u%c%I*u%c%s%c%I*u%c%s%c0%o\n", c, f->name, c, sizeof(ap->io->offset), ap->io->offset + ap->io->count, c, sizeof(f->st->st_size), f->st->st_size, c, VDB_DATE, n, sizeof(f->st->st_mtime), f->st->st_mtime, c, VDB_MODE, n, modex(f->st->st_mode & X_IPERM));
      return 1;
}

static int
vdb_puttrailer(Pax_t* pax, Archive_t* ap, File_t* f)
{
      if (state.record.trailer)
            paxwrite(pax, ap, state.record.trailer, state.record.trailerlen);
      return 0;
}

static off_t
vdb_putepilogue(Pax_t* pax, Archive_t* ap)
{
      register Vdb_t*   vdb = (Vdb_t*)ap->data;

      if (state.record.header)
            paxwrite(pax, ap, state.record.header, state.record.headerlen);
      sfprintf(vdb->directory, "%c%s%c%0*I*d%c%0*I*d\n", VDB_DELIMITER, VDB_DIRECTORY, VDB_DELIMITER, VDB_FIXED, sizeof(ap->io->offset), ap->io->offset + ap->io->count + sizeof(VDB_DIRECTORY), VDB_DELIMITER, VDB_FIXED, sizeof(Sfoff_t), sftell(vdb->directory) - sizeof(VDB_DIRECTORY) + VDB_LENGTH + 1);
      paxwrite(pax, ap, sfstrbase(vdb->directory), sfstrtell(vdb->directory));
      sfstrclose(vdb->directory);
      return ap->io->count;
}

Format_t    pax_vdb_format =
{
      "vdb",
      0,
      "virtual database",
      0,
      ARCHIVE|NOHARDLINKS|IN|OUT,
      DEFBUFFER,
      DEFBLOCKS,
      0,
      PAXNEXT(pax_vdb_next),
      0,
      vdb_done,
      vdb_getprologue,
      vdb_getheader,
      0,
      0,
      0,
      vdb_putprologue,
      vdb_putheader,
      0,
      vdb_puttrailer,
      vdb_putepilogue,
};

PAXLIB(&pax_vdb_format)

Generated by  Doxygen 1.6.0   Back to index