Logo Search packages:      
Sourcecode: ksh version File versions

pax-saveset.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 vmsbackup format
 */

#include "format.h"

#define BLKHDR_SIZE     256
#define BLKHDR_hdrsiz   0
#define BLKHDR_blksiz   40

#define FILHDR_SIZE     4
#define FILHDR_MAGIC    257
#define FILHDR_namelen  128
#define FILHDR_size     0
#define FILHDR_type     2
#define FILHDR_data     4

#define FILATT_blocks   10
#define FILATT_frag     12
#define FILATT_recatt   1
#define FILATT_recfmt   0
#define FILATT_reclen   2
#define FILATT_recvfc   15

#define RECHDR_SIZE     16
#define RECHDR_size     0
#define RECHDR_type     2

#define REC_file  3
#define REC_vbn         4

typedef struct Saveset_s
{
      char*       block;            /* current block        */
      long        blocksize;  /* max block size       */
      char*       bp;         /* block pointer        */
      int         recatt;           /* record attributes          */
      int         recfmt;           /* record format        */
      int         reclen;           /* record length        */
      int         recvfc;           /* record fixed control length      */
      int         lastsize;   /* size of last record        */
      time_t            time;       /* backup time                */
      char        id[17];           /* name id              */
} Saveset_t;

/*
 * get next saveset record
 * if header!=0 then all records skipped until REC_file found
 * otherwise REC_vbn cause non-zero return
 * 0 returned for no record match
 */

static int
getsaveset(Pax_t* pax, register Archive_t* ap, register File_t* f, register Saveset_t* ss, int header)
{
      register char*    p;
      register char*    s;
      char*       t;
      int         i;
      long        n;

      for (;;)
      {
            ss->bp += ss->lastsize;
            while (ss->bp >= ss->block + state.blocksize)
            {
                  ss->bp = ss->block;
                  ss->lastsize = 0;
                  if (paxread(pax, ap, ss->bp, (off_t)0, (off_t)state.blocksize, 0) <= 0)
                  {
                        ap->format = getformat("slt", 1);
                        if (header)
                              gettrailer(ap, f);
                        return 0;
                  }
                  if (swapget(1, ss->bp + BLKHDR_hdrsiz, 2) != BLKHDR_SIZE)
                        error(3, "invalid %s format block header", ap->format->name);
                  if (!(n = swapget(3, ss->bp + BLKHDR_blksiz, 4)))
                        ss->bp += state.blocksize;
                  else if (n != state.blocksize)
                        error(3, "invalid %s format blocksize=%ld", ap->format->name, n);
                  ss->bp += BLKHDR_SIZE;
            }
            ss->lastsize = swapget(1, ss->bp + RECHDR_size, 2);
            i = swapget(1, ss->bp + RECHDR_type, 2);
            ss->bp += RECHDR_SIZE;
            message((-2, "record: type=%d size=%d", i, ss->lastsize));
            if (i == REC_file)
            {
                  if (header)
                  {
                        p = ss->bp;
                        if (swapget(1, p, 2) != FILHDR_MAGIC)
                              error(3, "invalid %s format file header", ap->format->name);
                        p += 2;
                        i = swapget(1, p + FILHDR_size, 2);
                        if (p + FILHDR_data + i > ss->block + state.blocksize)
                              error(3, "invalid %s format file attribute", ap->format->name);
                        t = f->name = paxstash(pax, &ap->stash.head, NiL, i);
                        n = 0;
                        for (s = p + FILHDR_data + 1; s < p + FILHDR_data + i; s++)
                        {
                              if (isupper(*s))
                                    *t++ = tolower(*s);
                              else if (n)
                              {
                                    if (*s == ';')
                                          break;
                                    *t++ = *s;
                              }
                              else if (*s == ']')
                              {
                                    n = 1;
                                    *t++ = '/';
                              }
                              else if (*s == '.')
                                    *t++ = '/';
                              else
                                    *t++ = *s;
                        }
                        *t = 0;
                        for (i = 0; i < 5; i++)
                        {
                              s = p + FILHDR_size;
                              if ((p += FILHDR_SIZE + (long)swapget(1, s, 2)) > ss->block + state.blocksize)
                                    error(3, "invalid %s format file attribute", ap->format->name);
                        }
                        ss->recatt = *(p + FILHDR_data + FILATT_recfmt);
                        ss->recfmt = *(p + FILHDR_data + FILATT_recfmt);
                        ss->reclen = swapget(1, p + FILHDR_data + FILATT_reclen, 2);
                        ss->recvfc = swapget(1, p + FILHDR_data + FILATT_recvfc, 2);
                        f->st->st_size = (long)(swapget(1, p + FILHDR_data + FILATT_blocks, 2) - 1) * BLOCKSIZE + (long)swapget(1, p + FILHDR_data + FILATT_frag, 2);
                        for (; i < 15; i++)
                        {
                              s = p + FILHDR_size;
                              if ((p += FILHDR_SIZE + (long)swapget(1, s, 2)) > ss->block + state.blocksize)
                                    error(3, "invalid %s format file attribute", ap->format->name);
                        }

                        /*
                         * pure guesswork based on 100 nsec epoch
                         * 17-NOV-1858 00:00:00 GMT
                         */

                        if ((n = swapget(3, p + FILHDR_data + 4, 4) - 7355000) < 0)
                              n = 1;
                        else
                              n = (n << 8) + *(p + FILHDR_data + 3);
                        f->st->st_mtime = (time_t)n;
                        return 1;
                  }
                  ss->bp -= RECHDR_SIZE;
                  ss->lastsize = 0;
                  return 0;
            }
            else if (i == REC_vbn && !header)
                  return 1;
      }
}

static int
vmsbackup_done(Pax_t* pax, register Archive_t* ap)
{
      if (ap->data)
      {
            free(ap->data);
            ap->data = 0;
      }
      return 0;
}

static int
vmsbackup_getdata(Pax_t* pax, register Archive_t* ap, register File_t* f, int wfd)
{
      register Saveset_t*     ss = (Saveset_t*)ap->data;
      register off_t          c;
      int               i;
      int               j;
      int               k;
      Sfio_t*                 wfp;

      if (wfd < 0)
            wfp = 0;
      else if (!(wfp = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)))
      {
            error(2, "%s: cannot write", f->name);
            return -1;
      }
      j = 0;
      k = 0;
      c = 0;
      while (getsaveset(pax, ap, f, ss, 0))
      {
            /*
             * this part transcribed from vmsbackup
             */

            i = 0;
            if (wfp) while ((c + i) < f->st->st_size && i < ss->lastsize) switch (ss->recfmt)
            {
            case 1:     /* fixed length         */
                  if (j <= 0) j = ss->reclen;
                  sfputc(wfp, ss->bp[i]);
                  i++;
                  j--;
                  break;
            case 2:     /* variable length      */
            case 3:     /* with fixed control   */
                  if (j <= 0)
                  {
                        j = k = swapget(1, &ss->bp[i], 2);
                        i += 2;
                        if (ss->recfmt == 3)
                        {
                              i += ss->recvfc;
                              j -= ss->recvfc;
                        }
                  }
                  else
                  {
                        if (j == k && ss->recatt == 1)
                        {
                              if (ss->bp[i] == '0') ss->bp[i] = '\n';
                              else if (ss->bp[i] == '1') ss->bp[i] = '\f';
                        }
                        sfputc(wfp, ss->bp[i]);
                        i++;
                        j--;
                  }
                  if (j <= 0)
                  {
                        sfputc(wfp, '\n');
                        if (i & 1) i++;
                  }
                  break;
            case 4:     /* seq stream           */
            case 5:     /* seq LF stream  */
                  if (j <= 0) j = 512;
                  if (ss->bp[i] == '\n') j = 0;
                  else j--;
                  sfputc(wfp, ss->bp[i]);
                  i++;
                  break;
            case 6:     /* seq CR stream  */
                  if (ss->bp[i] == '\r') ss->bp[i] = '\n';
                  sfputc(wfp, ss->bp[i]);
                  i++;
                  break;
            default:
                  error(state.keepgoing ? 1 : 3, "%s: invalid %s format data record format=%d", f->name, ap->format->name, ss->recfmt);
                  goto next;
            }
      next:
            c += i;
      }
      if (wfp)
      {
            sfclose(wfp);
            setfile(ap, f);
      }
      return 1;
}

static int
vmsbackup_getepilogue(Pax_t* pax, Archive_t* ap)
{
      return 1;
}

static int
vmsbackup_validate(Pax_t* pax, Archive_t* ap, register File_t* f)
{
      register Saveset_t*     ss = (Saveset_t*)ap->data;
      register char*          s;

      if (f->type != X_IFREG)
      {
            error(2, "%s: only regular files copied in %s format", f->path, ap->format->name);
            return 0;
      }
      if (s = strrchr(f->name, '/'))
      {
            s++;
            error(1, "%s: file name stripped to %s", f->name, s);
      }
      else
            s = f->name;
      if (strlen(s) > sizeof(ss->id) - 1)
      {
            error(2, "%s: file name too long", f->name);
            return 0;
      }
      f->id = strupper(strcpy(ss->id, s));
      return 1;
}

Format_t    pax_vmsbackup_format =
{
      "vmsbackup",
      0,
      "VMS backup savset; for tape devices only",
      0,
      ARCHIVE|NOHARDLINKS|IN,
      0,
      0,
      0,
      PAXNEXT(pax_vmsbackup_next),
      0,
      vmsbackup_done,
      0,
      0,
      vmsbackup_getdata,
      0,
      vmsbackup_getepilogue,
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      vmsbackup_validate
};

PAXLIB(&pax_vmsbackup_format)

Generated by  Doxygen 1.6.0   Back to index