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

rar.c

#pragma prototyped

/*
 * pax rar format
 */

#include <paxlib.h>
#include <codex.h>
#include <swap.h>
#include <tm.h>

#define SUM             "sum-crc-0xedb88320-init-done"

typedef struct Ar_s
{
      Codexdisc_t       codexdisc;
      Pax_t*                  pax;
      Paxarchive_t*           ap;
      Sfio_t*                 sum;
      char              method[128];
      unsigned long           checksum;
      int               solid;

      unsigned short          level;
} Ar_t;

static int
rar_done(Pax_t* pax, register Paxarchive_t* ap)
{
      register Ar_t*    ar = (Ar_t*)ap->data;

      if (!ar)
            return -1;
      if (ar->sum)
            sfdisc(ar->sum, SF_POPDISC);
      free(ar);
      ap->data = 0;
      return 0;
}

static int
rar_getprologue(Pax_t* pax, Paxformat_t* fp, register Paxarchive_t* ap, Paxfile_t* f, unsigned char* buf, size_t size)
{
      register Ar_t*          ar;

      if (size < 7 || buf[0] != 0x52 || buf[1] != 0x61 || buf[2] != 0x72 || buf[3] != 0x21 || buf[4] != 0x1a || buf[5] != 0x07 || buf[6] != 0x00)
            return 0;
      if (!(ar = newof(0, Ar_t, 1, 0)))
      {
            if (ar)
                  free(ar);
            return paxnospace(pax);
      }
      ap->data = ar;
      ar->pax = pax;
      ar->ap = ap;
      codexinit(&ar->codexdisc, pax->errorf);
      ar->codexdisc.passphrase = pax->passphrase;
      if (!(ar->sum = codexnull()) || codex(ar->sum, NiL, SUM, 0, &ar->codexdisc, NiL) <= 0)
      {
            ar->sum = 0;
            rar_done(pax, ap);
            return -1;
      }
      return 1;
}

static int
rar_getheader(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f)
{
      register Ar_t*          ar = (Ar_t*)ap->data;
      register unsigned char* buf;
      char*             s;
      Tm_t              tm;
      unsigned short          checksum;
      unsigned short          flags;
      unsigned short          type;
      unsigned short          size;
      unsigned long           data;
      unsigned long           dostime;
      int               i;
      char*             msg;
      Codexdata_t       sum;

      msg = 0;
      for (;;)
      {
            if (!(buf = (unsigned char*)paxget(pax, ap, -7, NiL)))
                  return 0;
            checksum = swapget(3, buf+0, 2);
            type = buf[2];
            flags = swapget(3, buf+3, 2);
            if (flags & 0x0008)
                  ar->solid = 1;
            if ((size = swapget(3, buf+5, 2)) < 7)
                  break;
            if (!(size -= 7))
                  continue;
            sfsync(ar->sum);
            sfwrite(ar->sum, buf+2, 5);
            if (!(buf = (unsigned char*)paxget(pax, ap, size, NiL)))
            {
                  msg = "unexpected EOF";
                  break;
            }
            data = (flags & 0x8000) ? swapget(3, buf+0, 4) : 0;
            if (type != 0x74)
            {
                  if (data && paxseek(pax, ap, data, SEEK_CUR, 0) < 0)
                        break;
                  continue;
            }
            sfwrite(ar->sum, buf, size);
            codexdata(ar->sum, &sum);
            if (paxchecksum(pax, ap, NiL, checksum, sum.num & 0xffff))
                  return -1;
            f->uncompressed = swapget(3, buf+4, 4);
            if (flags & 0x0100)
            {
                  data += swapget(3, buf+25, 4) << 32;
                  f->uncompressed += swapget(3, buf+29, 4);
            }
            f->st->st_size = data;
            ar->checksum = swapget(3, buf+9, 4);
            dostime = swapget(3, buf+13, 4);
            i = 0;
            if (flags & 0x0004)
                  i += sfsprintf(ar->method, sizeof(ar->method), "crypt-rar-%u%s+SIZE=%I*u|", buf[17], ar->solid ? "-RETAIN" : "", sizeof(f->st->st_size), f->st->st_size);
            if ((ar->level = buf[18]) == 0x30)
                  i += sfsprintf(ar->method + i, sizeof(ar->method) - i, "copy");
            else
                  i += sfsprintf(ar->method + i, sizeof(ar->method) - i, "rar-%u%s+SIZE=%I*u", buf[17], ar->solid ? "-RETAIN" : "", sizeof(f->uncompressed), f->uncompressed);
            sfsprintf(ar->method + i, sizeof(ar->method) - i, "|%s", SUM);
            i = swapget(3, buf+19, 2);
            f->name = paxstash(pax, &ap->stash.head, NiL, i + 1);
            memcpy(f->name, buf + ((flags & 0x0100) ? 33 : 25), i);
            f->name[i] = 0;
            f->linkpath = 0;
            f->st->st_dev = 0;
            f->st->st_ino = 0;
            i = swapget(3, buf+21, 4);
            if (buf[8] <= 2)
            {
                  if (i & 0x10)
                        i = X_IFDIR|X_IRUSR|X_IWUSR|X_IXUSR|X_IRGRP|X_IWGRP|X_IXGRP|X_IROTH|X_IWOTH|X_IXOTH;
                  else if (i & 0x01)
                        i = X_IFREG|X_IRUSR|X_IRGRP|X_IROTH;
                  else
                  {
                        i = X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IWGRP|X_IROTH|X_IWOTH;
                        if ((s = strrchr(f->name, '.')) && (s[1]=='e' || s[1]=='E') && (s[1]=='x' || s[1]=='X') && (s[1]=='e' || s[1]=='E'))
                              i |= X_IXUSR|X_IXGRP|X_IXOTH;
                  }
            }
            if ((flags & 0x00e0) == 0x00e0 && (i & X_IFMT) != X_IFDIR)
            {
                  i = X_IFDIR|(i & ~X_IFMT)|X_IRUSR|X_IWUSR|X_IXUSR;
                  if (i & (X_IROTH|X_IWOTH))
                        i |= X_IROTH|X_IXOTH;
                  else
                  {
                        i &= ~(X_IROTH|X_IXOTH);
                        if (i & (X_IRGRP|X_IWGRP))
                              i |= X_IRGRP|X_IXGRP;
                        else
                              i &= ~(X_IRGRP|X_IXGRP);
                  }
            }
            f->st->st_mode = i & pax->modemask;
            f->st->st_uid = pax->uid;
            f->st->st_gid = pax->gid;
            f->st->st_nlink = 1;
            IDEVICE(f->st, 0);
            memset(&tm, 0, sizeof(tm));
            tm.tm_year  = ((dostime >> (16+9)) & 0x7f) + 80;
            tm.tm_mon   = ((dostime >> (16+5)) & 0x0f) - 1;
            tm.tm_mday  = ((dostime >> (16+0)) & 0x1f);
            tm.tm_hour  = ((dostime >>     11) & 0x1f);
            tm.tm_min   = ((dostime >>      5) & 0x3f);
            tm.tm_sec   = ((dostime          ) & 0x1f) * 2;
            f->st->st_mtime = f->st->st_ctime = f->st->st_atime = tmtime(&tm, TM_LOCALZONE);
            return 1;
      }
      return paxcorrupt(pax, ap, f, msg);
}

static int
rar_getdata(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f, int fd)
{
      register Ar_t*    ar = (Ar_t*)ap->data;
      Sfio_t*           sp;
      off_t       pos;
      ssize_t           n;
      int         r;
      int         pop;
      Codexdata_t sum;

      if (!f->st->st_size)
            return 1;
      pos = paxseek(pax, ap, 0, SEEK_CUR, 0) + f->st->st_size;
      r = -1;
      if (fd < 0 && !ar->solid)
            r = 1;
      else if (sp = paxpart(pax, ap, f->st->st_size))
      {
            if ((pop = codex(sp, NiL, ar->method, 0, &ar->codexdisc, NiL)) < 0)
                  (*pax->errorf)(NiL, pax, 2, "%s: %s: cannot decode method %s", ap->name, f->name, ar->method);

            else
            {
                  for (;;)
                  {
                        if ((n = sfread(sp, pax->buf, sizeof(pax->buf))) < 0)
                        {
                              (*pax->errorf)(NiL, pax, 2, "%s: %s: unexpected EOF", ap->name, f->name);
                              break;
                        }
                        else if (n == 0)
                        {
                              if (codexdata(sp, &sum) <= 0)
                                    (*pax->errorf)(NiL, pax, 2, "%s: %s: checksum discipline error", ap->name, f->name);
                              else if (!paxchecksum(pax, ap, f, ar->checksum, sum.num))
                                    r = 1;
                              break;
                        }
                        if (fd >= 0 && paxdata(pax, ap, f, fd, pax->buf, n))
                              break;
                  }
                  codexpop(sp, NiL, pop);
            }
      }
      if (paxseek(pax, ap, pos, SEEK_SET, 0) != pos)
      {
            (*pax->errorf)(NiL, pax, 2, "%s: %s: cannot seek past %s format data", ap->name, f->name, ap->format->name);
            r = -1;
      }
      return r;
}

Paxformat_t pax_rar_format =
{
      "rar",
      0,
      "rar archive",
      0,
      PAX_ARCHIVE|PAX_DOS|PAX_NOHARDLINKS|PAX_IN,
      PAX_DEFBUFFER,
      PAX_DEFBLOCKS,
      0,
      PAXNEXT(pax_rar_next),
      0,
      rar_done,
      rar_getprologue,
      rar_getheader,
      rar_getdata,
};

PAXLIB(&pax_rar_format)

Generated by  Doxygen 1.6.0   Back to index