home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / compress / xfh132.lzh / XFH / src / xpk.c < prev   
C/C++ Source or Header  |  1993-01-19  |  38KB  |  1,304 lines

  1. /* xpk.c - routines for the master xpk.library. 
  2.    Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
  3.  
  4.    This file is part of XFH, the compressing file system handler.
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            */
  19.  
  20. /* $Log:    xpk.c,v $
  21.  * Revision 1.2  93/01/14  15:25:12  Kristian
  22.  * Added RCS keywords
  23.  * 
  24.  */
  25.  
  26.  
  27. #include "CFS.h"
  28. #include <dossupport.h>
  29.  
  30. #include <exec/ports.h>
  31. #include <exec/libraries.h>
  32. #include <utility/hooks.h>
  33. #include <utility/tagitem.h>
  34.  
  35. #include <proto/exec.h>
  36. #include <proto/dos.h>
  37.  
  38. #ifdef __GNUC__
  39. #include "my_alib_protos.h"    /* Because of bug in inline/exec.h */
  40. #else
  41. #include <clib/alib_protos.h>
  42. #endif
  43.  
  44. #ifdef __GNUC__
  45. #define NO_XPK_PROTOS 1
  46. #define NO_VARARGS_INLINE 1
  47. #endif
  48. #include <libraries/xpk.h>
  49. #include <proto/xpk.h>
  50.  
  51. /* These two include files are changing all the time. Hence the #undef. */
  52. #undef XpkFH
  53.  
  54. struct Library *XpkBase;
  55.  
  56.  
  57. #ifndef min
  58. #define min(a,b) ((a)>(b) ? (b) : (a))
  59. #endif
  60.  
  61. /* 'Conditional' tag - passed only if condition true. */
  62. #define TAGIF(c,t) ((c)?(t):TAG_IGNORE)
  63.  
  64. /* Structure for holding an xpk file unpacked in memory. */
  65. struct unpackedxpk {
  66.   struct xpkmemchunk *first,*last,*current;
  67.   LONG currentpos;
  68. };
  69.  
  70. /* Node in linked list of data buffers. */
  71. struct xpkmemchunk {
  72.   struct xpkmemchunk *next;
  73.   LONG abspos;
  74.   LONG size;
  75.   UBYTE *data;      /* MUST be alloced with dosalloc(). */
  76. };
  77.  
  78. struct XpkFH {
  79.   struct CFSFH cfsfh;
  80.   struct unpackedxpk *unpackedxpk;
  81.   LONG filelen;
  82.   UBYTE *InBuf;     /* Buffer last returned by inhook. */
  83.   UBYTE *OutBuf;    /* Buffer last returned by outhook. */
  84.   LONG InBufLen;    /* Of InBuf. (ToDo: Not really used...) */
  85.   LONG OutBufLen;   /* Of OutBuf. (ToDo: Not really used...) */
  86. };
  87.  
  88. struct XpkLock {
  89.   struct CFSLock cfslock;
  90. };
  91.  
  92.  
  93.  
  94. static struct unpackedxpk *newunpackedxpk(void){
  95.   struct unpackedxpk *p;
  96.   
  97.   if(!dalloc(p)) return NULL;
  98.   /* All fields 0 by default. */
  99.   return p;
  100. }
  101.  
  102. /* NOTE: 'data' should be allocated with dosalloc().
  103.  * NOTE ALSO: Memory block may be larger than 'size' (will be freed by
  104.  * dosfree() ).
  105.  */
  106. static BOOL addxpkmemchunk(struct unpackedxpk *p, UBYTE *data, LONG size ){
  107.   struct xpkmemchunk *q;
  108.   
  109.   if(!(dalloc(q))) return FALSE;
  110.   q->next=NULL;
  111.   q->size=size;
  112.   q->data=data;
  113.   if(!p->first){
  114.     q->abspos = 0L;
  115.     p->first=p->current=p->last = q;
  116.   }else{
  117.     q->abspos = p->last->abspos+p->last->size;
  118.     p->last->next = q;
  119.     p->last = q;
  120.   }
  121.   return TRUE;
  122. }
  123.  
  124. static void killunpackedxpk(struct unpackedxpk *p){
  125.   struct xpkmemchunk *q,*r;
  126.   
  127.   for(q=p->first;q;q=r){
  128.     r=q->next;
  129.     dfree(q->data);
  130.     dfree(q);
  131.   }
  132.   dfree(p);
  133. }
  134.  
  135. static BOOL seekunpackedxpk(struct unpackedxpk *p, LONG abspos){
  136.    struct xpkmemchunk *q;
  137.    
  138.    if(abspos < 0 || !p->first || p->last->abspos+p->last->size < abspos)
  139.       return abspos == 0;
  140.    /* Special case: seek just beyond end. */
  141.    if(p->last->abspos+p->last->size == abspos){
  142.         debug(("Seeking to last position in file: %ld.\n",abspos));
  143.       p->current = p->last;
  144.       p->currentpos = abspos;
  145.         return DOSTRUE;
  146.    }
  147.    /* Start at current pos. if possible. */
  148.    q = p->current->abspos <= abspos ? p->current : p->first;
  149.    while(q->abspos+q->size <= abspos) q = q->next;
  150.    p->current = q;
  151.    p->currentpos = abspos;
  152.    return DOSTRUE;
  153. }
  154.  
  155. static BOOL readunpackedxpk(struct unpackedxpk *p, UBYTE *buf, LONG size){
  156.    struct xpkmemchunk *q;
  157.    LONG len,chunkpos;
  158.    
  159.    if(!p->first)
  160.       return size==0;
  161.    q = p->current;
  162.    while(size>0){
  163.       if(p->last->abspos+p->last->size <= p->currentpos) return FALSE;
  164.       chunkpos=p->currentpos-q->abspos;
  165.       len = min(size,q->size-chunkpos);
  166.       CopyMem(q->data+chunkpos,buf,len);
  167.       size-=len;
  168.       buf+=len;
  169.       p->currentpos+=len;
  170.       if(p->currentpos >= q->abspos+q->size) q=q->next;
  171.       if(q) p->current = q;
  172.    }
  173.    return TRUE;
  174. }
  175.  
  176.  
  177.  
  178. /*------------------------------------------------------------------------*
  179.  * Hooks for Xpk packing / unpacking.
  180.  */
  181.  
  182. /* Structure for private hook data (glob & Xpkfilehandle). */
  183. struct xpkhookdata {
  184.    glb glob;
  185.    struct XpkFH *fh;
  186. };
  187.  
  188.  
  189. /* Free Xpk input buffer if nessesary. */
  190. static void FreeXpkInBuf(struct XpkFH *fh){
  191.  
  192.    /* debug(("FreeXpkInBuf: Checking if buffers allocated...\n")); */
  193.    if(fh->InBuf){
  194.       /* debug(("FreeXpkInBuf: Freeing buffer: %lx,%ld.\n",fh->InBuf,fh->InBufLen)); */
  195.       dosfree(fh->InBuf);
  196.       fh->InBuf = NULL;
  197.    }
  198. }
  199.  
  200. /* Allocate Xpk input buffer. */
  201. static UBYTE *AllocXpkInBuf(struct XpkFH *fh, LONG size){
  202.  
  203.    /* NOTE: I found out (the hard way...) that Xpk expects a buffer
  204.     * 4 bytes larger than requested ... wierd. */
  205.    size+=4;
  206.    FreeXpkInBuf(fh);
  207.    fh->InBufLen=size;
  208.    if(!(fh->InBuf=dosalloc(size))){
  209.       return 0L;
  210.    }
  211.    return fh->InBuf;
  212. }
  213.  
  214. /* Free Xpk output buffer if nessesary. */
  215. static void FreeXpkOutBuf(struct XpkFH *fh){
  216.  
  217.    /* debug(("FreeXpkOutBuf: Checking if buffers allocated...\n")); */
  218.    if(fh->OutBuf){
  219.       /* debug(("FreeXpkOutBuf: Freeing buffer: %lx,%ld.\n",fh->OutBuf,fh->OutBufLen)); */
  220.       dosfree(fh->OutBuf);
  221.       fh->OutBuf = NULL;
  222.    }
  223. }
  224.  
  225. /* Allocate Xpk output buffer. */
  226. static UBYTE *AllocXpkOutBuf(struct XpkFH *fh, LONG size){
  227.  
  228.    /* NOTE: I found out (the hard way...) that Xpk expects a buffer
  229.     * 4 bytes larger than requested ... wierd. */
  230.    size+=4;
  231.    FreeXpkOutBuf(fh);
  232.    fh->OutBufLen=size;
  233.    if(!(fh->OutBuf=dosalloc(size))){
  234.       return 0L;
  235.    }
  236.    return fh->OutBuf;
  237. }
  238.  
  239. /* Transfer control to actual hook function. Shields the actual */
  240. /* hook functions from any ugly assembler-like register considerations. */
  241.  
  242. #ifdef __GNUC__
  243. static LONG DoXpkHook(void){
  244.   register struct Hook *rega0       asm("a0");
  245.   struct Hook *hook=rega0;
  246.   register struct XpkIOMsg *rega1   asm("a1");
  247.   struct XpkIOMsg *msg=rega1;
  248.   register void *rega2              asm("a2");
  249.   void *dummy=rega2;
  250. #else
  251. static LONG __asm DoXpkHook( register __a0 struct Hook *hook,
  252.                       register __a1 struct XpkIOMsg *msg,
  253.                       register __a2 void *dummy){
  254. #endif
  255.   struct xpkhookdata *hookdata = hook->h_Data;
  256.   LONG ret;
  257.   typedef LONG (*myhooktype)(glb, struct XpkFH *, ULONG, UBYTE **, LONG);
  258.    
  259.   ret = (*(myhooktype)hook->h_SubEntry)
  260.     (hookdata->glob, hookdata->fh,msg->Type,(UBYTE **)&msg->Ptr,msg->Size);
  261.   if(ret) msg->IOError = hookdata->glob->ioerr;
  262.   return ret;
  263. }
  264.  
  265.  
  266. /* Calling conventions for hooks. */
  267. /* ToDo: When docs become available, check against this description. */
  268. /* */
  269. /* XpkIOMsg->IOError is set only in case of non-zero hook return value. */
  270. /* */
  271. /* Big problem: What is XIO_SEEK supposed to return in XpkIOMsg->Ptr? */
  272. /* The masterlib does the wierdest things... However, it (currently!) */
  273. /* only needs a non-zero return in case of succes. */
  274. /* */
  275. /* XIO_GETBUF/XIO_WRITE in xpkunpackout(): It is assumed that only one */
  276. /* buffer will be needed at any time, so that a second XIO_GETBUF may */
  277. /* free the buffer returned by the first. It is also assumed that */
  278. /* XIO_WRITE may grab the buffer it is writing if it was allocated by */
  279. /* XIO_GETBUF. */
  280. /* */
  281.  
  282. /* Read() hook for unpacking. */
  283. static LONG xpkunpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  284.    LONG actuallen;
  285.    
  286. /* debug(("UnpackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
  287.    switch(type){
  288.      case XIO_READ:
  289.       if(!*buf){
  290.          if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  291.       }
  292.       if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
  293.          return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
  294.       }
  295.       break;
  296.      case XIO_WRITE:
  297.       debug(("Error: xpkunpackin(): Xpk attemps to XIO_WRITE.\n"));
  298.       return XPKERR_NOFUNC;
  299.      case XIO_FREE:
  300.      case XIO_ABORT:
  301.       FreeXpkInBuf(fh); 
  302.       break;
  303.      case XIO_GETBUF:
  304.       if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  305.       break;
  306.      case XIO_SEEK:
  307.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  308.          return XPKERR_IOERROUT;
  309.       }
  310.       *buf = (APTR) 4L;   /* VERY strange... */
  311.       break;
  312.      case XIO_TOTSIZE:
  313.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  314.       break;
  315.      default:
  316.       debug(("*** PANIC: xpkunpackin(): Unknown type of action requested.\n"));
  317.       return XPKERR_NOFUNC;
  318.    }
  319.    
  320.    return XPKERR_OK;
  321. }
  322.  
  323.  
  324. /* Write() hook for unpacking. */
  325. static LONG xpkunpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  326.    
  327. /* debug(("UnpackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size)); */
  328.    switch(type){
  329.      case XIO_READ:
  330.       debug(("Error: xpkunpackout(): Xpk attemps to XIO_READ.\n"));
  331.       return XPKERR_NOFUNC;
  332.      case XIO_WRITE:
  333.       if( *buf == fh->OutBuf /* && size == fh->OutBufLen */ ){
  334.          /* Writing our previously allocated buffer. Just add it to */
  335.          /* the filehandle, and mark it as used. */
  336.             /* NOTE: because of safety margin, the added memory block is */
  337.             /* larger than nesseeary. */
  338.  
  339.          /* debug(("Adding previously allocated buffer to filehandle: %lx\n",*buf)); */
  340.          if(!addxpkmemchunk(fh->unpackedxpk,*buf,size)){
  341.             debug(("Error: xpkunpackout(): Cannot add data.\n"));
  342.             return XPKERR_NOMEM;
  343.          }
  344.          fh->OutBuf = NULL;
  345.          fh->OutBufLen = 0L;
  346.       }else{
  347.          UBYTE *newbuf;
  348.          
  349.          /* debug(("Copying data into filehandle.\n")); */
  350.          if( !(newbuf = dosalloc(size)) ){
  351.             debug(("Error: xpkunpackout(): No memory.\n"));
  352.             return XPKERR_NOMEM;
  353.          }
  354.          CopyMem(*buf,newbuf,size);
  355.          if(!addxpkmemchunk(fh->unpackedxpk,newbuf,size)){
  356.             debug(("Error: xpkunpackout(): Cannot add data.\n"));
  357.             dosfree(newbuf);
  358.             return XPKERR_NOMEM;
  359.          }
  360.       }
  361.       break;
  362.      case XIO_FREE:
  363.      case XIO_ABORT:
  364.       FreeXpkOutBuf(fh);
  365.       break;
  366.      case XIO_GETBUF:
  367.       if( !(*buf = AllocXpkOutBuf(fh,size)) ){
  368.          debug(("Error: xpkunpackout(): Cannot get buffer for xpk.\n"));
  369.          return XPKERR_NOMEM;
  370.       }
  371.       /* debug(("xpkunpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
  372.       break;
  373.      case XIO_SEEK:
  374.         /* Strange... Surely this code is wrong? I mean, there's no file
  375.          * handle, is there? Commented out for now. */
  376. /*      if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){ */
  377. /*         return XPKERR_IOERROUT; */
  378. /*      } */
  379. /*      *buf = (APTR) 4L;   /* VERY strange... */
  380.       debug(("Error: xpkunpackout(): Xpk attempts to XIO_SEEK.\n"));
  381.       return XPKERR_NOFUNC;
  382. /*      break; */
  383.      case XIO_TOTSIZE:
  384.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  385.       break;
  386.      default:
  387.       debug(("*** PANIC: xpkunpackout(): Unknown type of action requested.\n"));
  388.       return XPKERR_NOFUNC;
  389.    }
  390.    return XPKERR_OK;
  391. }
  392.  
  393.  
  394. /* Hooks for Xpk packing.
  395.  * Currently, these use simple XpkFH file handles. However, I'm hoping
  396.  * to eventually make them use async I/O.
  397.  * NOTE BIEN: these XpkFH are FAKE, and cannot be used as such safely.
  398.  * Specifically, the cfsfh is not valid (though cfsfh.xfh is).
  399.  */
  400.  
  401. /* NOTE: xpkpackin() / xpkpackout() are also used for unpacking. */
  402. /* Read() hook for packing. */
  403. static LONG xpkpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  404.    LONG actuallen;
  405.    
  406. /* debug(("PackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
  407.    switch(type){
  408.      case XIO_READ:
  409.       if(!*buf){
  410.          if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  411.       }
  412.       if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
  413.          return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
  414.       }
  415.       break;
  416.      case XIO_WRITE:
  417.       debug(("Error: xpkpackin(): Xpk attemps to XIO_WRITE.\n"));
  418.       return XPKERR_NOFUNC;
  419.      case XIO_FREE:
  420.      case XIO_ABORT:
  421.       FreeXpkInBuf(fh); 
  422.       break;
  423.      case XIO_GETBUF:
  424.       if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
  425.       break;
  426.      case XIO_SEEK:
  427.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  428.          return XPKERR_IOERROUT;
  429.       }
  430.       *buf = (APTR) 4L;   /* VERY strange... */
  431.       break;
  432.      case XIO_TOTSIZE:
  433.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  434.       break;
  435.      default:
  436.       debug(("*** PANIC: xpkpackin(): Unknown type of action requested.\n"));
  437.       return XPKERR_NOFUNC;
  438.    }
  439.    
  440.    return XPKERR_OK;
  441. }
  442.  
  443.  
  444. /* Write() hook for packing. */
  445. static LONG xpkpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
  446.    
  447. /* debug(("PackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size));*/
  448.    switch(type){
  449.      case XIO_READ:
  450.       debug(("Error: xpkpackout(): Xpk attemps to XIO_READ.\n"));
  451.       return XPKERR_NOFUNC;
  452.      case XIO_WRITE:
  453.       if(xWrite(glob, fh->cfsfh.xfh, *buf, size) != size){
  454.          return XPKERR_IOERROUT;
  455.       }
  456.       break;
  457.      case XIO_FREE:
  458.      case XIO_ABORT:
  459.       FreeXpkOutBuf(fh);
  460.       break;
  461.      case XIO_GETBUF:
  462.       if( !(*buf = AllocXpkOutBuf(fh,size)) ){
  463.          debug(("Error: xpkpackout(): Cannot get buffer for xpk.\n"));
  464.          return XPKERR_NOMEM;
  465.       }
  466.       /* debug(("xpkpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
  467.       break;
  468.      case XIO_SEEK:
  469.       if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
  470.          return XPKERR_IOERROUT;
  471.       }
  472.       *buf = (APTR) 4L;   /* VERY strange... */
  473.       break;
  474.      case XIO_TOTSIZE:
  475.       /* debug(("..... XIO_TOTSIZE: no action...\n")); */
  476.       break;
  477.      default:
  478.       debug(("*** PANIC: xpkpackout(): Unknown type of action requested.\n"));
  479.       return XPKERR_NOFUNC;
  480.    }
  481.    return XPKERR_OK;
  482. }
  483.  
  484.  
  485.  
  486. /*------------------------------------------------------------------------*
  487.  * Low-level interface to Xpk functions.
  488.  */
  489.  
  490.  
  491. /* The following code is there to support pre-2.0 OS versions. The
  492.  * problem is that Xpk insists on doing OpenLibrary() itself, which
  493.  * causes the dreaded ASYNCPKT guru.
  494.  */
  495.  
  496. struct xpkunpackmsg{
  497.    struct Message msg;
  498.    void (*func)();
  499.    glb glob;
  500.    struct TagItem *tags;
  501.    LONG result;
  502. };
  503.  
  504. struct xpkexammsg{
  505.    struct Message msg;
  506.    void (*func)();
  507.    glb glob;
  508.    struct XpkFib *fib;
  509.    struct TagItem *tags;
  510.    LONG result;
  511. };
  512.  
  513. struct xpkpackmsg{
  514.    struct Message msg;
  515.    void (*func)();
  516.    glb glob;
  517.    struct TagItem *tags;
  518.    LONG result;
  519. };
  520.  
  521. #ifdef __GNUC__
  522. static void CallXpkUnpackTags(void){
  523.   register struct xpkunpackmsg *rega0   asm("a0");
  524.   struct xpkunpackmsg *msg=rega0;
  525. #else
  526. static void __asm CallXpkUnpackTags(register __a0 struct xpkunpackmsg *msg){
  527. #endif
  528.    struct MsgPort *port;
  529.    
  530.    debug(("Calling XpkUnpack(%lx)...", msg->tags ));
  531.    port = msg->glob->ioport;
  532.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  533.       msg -> result = XpkUnpack(msg->tags);
  534.       DeletePort(msg->glob->ioport);
  535.    }else{
  536.       debug(("(no port)"));
  537.       msg->result = XPKERR_NOMEM;
  538.    }
  539.    msg->glob->ioport = port;
  540.    debug(("=%ld\n",msg->result));
  541. }
  542.  
  543.  
  544. #ifdef __GNUC__
  545. static void CallXpkExamine(void){
  546.   register struct xpkexammsg *rega0   asm("a0");
  547.   struct xpkexammsg *msg=rega0;
  548. #else
  549. static void __asm CallXpkExamine(register __a0 struct xpkexammsg *msg){
  550. #endif
  551.    struct MsgPort *port;
  552.    
  553.    debug(("Calling XpkExamine(%lx,%lx)...", msg->fib, msg->tags ));
  554.    port = msg->glob->ioport;
  555.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  556.       msg -> result = XpkExamine(msg->fib, msg->tags);
  557.       DeletePort(msg->glob->ioport);
  558.    }else{
  559.       debug(("(no port)"));
  560.       msg->result = XPKERR_NOMEM;
  561.    }
  562.    msg->glob->ioport = port;
  563.    debug(("=%ld\n",msg->result));
  564. }
  565.  
  566.  
  567. #ifdef __GNUC__
  568. static void CallXpkPackTags(void){
  569.   register struct xpkpackmsg *rega0   asm("a0");
  570.   struct xpkpackmsg *msg=rega0;
  571. #else
  572. static void __asm CallXpkPackTags(register __a0 struct xpkpackmsg *msg){
  573. #endif
  574.    struct MsgPort *port;
  575.    
  576.    debug(("Calling XpkPack(%lx)...", msg->tags ));
  577.    port = msg->glob->ioport;
  578.    if(msg->glob->ioport=CreatePort(NULL,0L)){
  579.       msg -> result = XpkPack(msg->tags);
  580.       DeletePort(msg->glob->ioport);
  581.    }else{
  582.       debug(("(no port)"));
  583.       msg->result = XPKERR_NOMEM;
  584.    }
  585.    msg->glob->ioport = port;
  586.    debug(("=%ld\n",msg->result));
  587. }
  588.  
  589.  
  590. static LONG MyXpkUnpackTags( glb glob, ULONG firsttag, ... ){
  591.    /* Cannot call xpk from a Task (or handler) before KS 2.0. */
  592.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  593.       return XpkUnpack( (struct TagItem *)&firsttag );
  594.    }else{
  595.       struct xpkunpackmsg msg,*msg2;
  596.       extern void DoDOSSeg();
  597.       struct MsgPort *procid;
  598.    
  599.       msg.msg.mn_Node.ln_Succ=NULL;
  600.       msg.msg.mn_Node.ln_Pred=NULL;
  601.       msg.msg.mn_Node.ln_Name=NULL;
  602.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  603.       msg.msg.mn_Node.ln_Pri=0;
  604.       msg.msg.mn_ReplyPort=glob->xpkport;
  605.       msg.msg.mn_Length=sizeof(msg);
  606.       msg.func=CallXpkUnpackTags;
  607.       msg.glob = glob;
  608.       msg.tags = (struct TagItem *)&firsttag;
  609.  
  610.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  611.         ("XpkUnpack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  612.         return XPKERR_NOMEM;
  613.    
  614.       PutMsg(procid,(struct Message *)&msg);
  615.       do WaitPort(glob->xpkport);
  616.       while(!(msg2=(struct xpkunpackmsg *)GetMsg(glob->xpkport)));
  617.  
  618. #ifdef DEBUG
  619.       if(msg2!=&msg)
  620.          dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  621. #endif
  622.       return msg2->result;
  623.    }
  624. }
  625.  
  626. static LONG MyXpkExamine( glb glob, struct XpkFib *fib, ULONG firsttag, ... ){
  627.    /* Cannot call xpk from a Task (or handler) before KS 2.0. */
  628.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  629.       return XpkExamine( fib, (struct TagItem *)&firsttag );
  630.    }else{
  631.       struct xpkexammsg msg,*msg2;
  632.       extern void DoDOSSeg();
  633.       struct MsgPort *procid;
  634.    
  635.       msg.msg.mn_Node.ln_Succ=NULL;
  636.       msg.msg.mn_Node.ln_Pred=NULL;
  637.       msg.msg.mn_Node.ln_Name=NULL;
  638.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  639.       msg.msg.mn_Node.ln_Pri=0;
  640.       msg.msg.mn_ReplyPort=glob->xpkport;
  641.       msg.msg.mn_Length=sizeof(msg);
  642.       msg.func=CallXpkExamine;
  643.       msg.glob = glob;
  644.       msg.fib = fib;
  645.       msg.tags = (struct TagItem *)&firsttag;
  646.  
  647.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  648.         ("XpkExamine()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  649.         return XPKERR_NOMEM;
  650.    
  651.       PutMsg(procid,(struct Message *)&msg);
  652.       do WaitPort(glob->xpkport);
  653.       while(!(msg2=(struct xpkexammsg *)GetMsg(glob->xpkport)));
  654.  
  655. #ifdef DEBUG
  656.       if(msg2!=&msg)
  657.          dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  658. #endif
  659.       return msg2->result;
  660.    }
  661. }
  662.  
  663. static LONG MyXpkPackTags( glb glob, ULONG firsttag, ... ){
  664.    /* Cannot call Xpk from a Task (or handler) before KS 2.0. */
  665.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  666.       return XpkPack( (struct TagItem *)&firsttag );
  667.    }else{
  668.       struct xpkpackmsg msg,*msg2;
  669.       extern void DoDOSSeg();
  670.       struct MsgPort *procid;
  671.    
  672.       msg.msg.mn_Node.ln_Succ=NULL;
  673.       msg.msg.mn_Node.ln_Pred=NULL;
  674.       msg.msg.mn_Node.ln_Name=NULL;
  675.       msg.msg.mn_Node.ln_Type=NT_MESSAGE;
  676.       msg.msg.mn_Node.ln_Pri=0;
  677.       msg.msg.mn_ReplyPort=glob->xpkport;
  678.       msg.msg.mn_Length=sizeof(msg);
  679.       msg.func=CallXpkPackTags;
  680.       msg.glob = glob;
  681.       msg.tags = (struct TagItem *)&firsttag;
  682.  
  683.       if(!(procid=CreateProc   /* Lets pray that 10K stack is enough... */
  684.         ("XpkPack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
  685.         return XPKERR_NOMEM;
  686.    
  687.       PutMsg(procid,(struct Message *)&msg);
  688.       do WaitPort(glob->xpkport);
  689.       while(!(msg2=(struct xpkpackmsg *)GetMsg(glob->xpkport)));
  690.  
  691. #ifdef DEBUG
  692.       if(msg2!=&msg)
  693.          dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
  694. #endif
  695.       return msg2->result;
  696.    }
  697. }
  698.  
  699.  
  700. /* This function opens an existing file in the xpk format, unpacking
  701.  * it to memory with the help of the xpk.library. Note that due to
  702.  * limitation in the current interface of xpk.library, the whole file
  703.  * must be unpacked at once, which is more speed efficient (and by far
  704.  * the easiest to implement), but requires rather a lot of memory
  705.  * (potentially requiring the data to reside 2-3 times in main memory
  706.  * simultaneously) and could result in memory fragmentation.
  707.  */
  708. struct XpkFH *XpkOpenOldFile( glb glob, struct FileHandle *xfh ){
  709.    struct XpkFH *fh;
  710.    LONG res;
  711.    LONG inlen;
  712.    struct Hook inhook,outhook;
  713.    struct xpkhookdata indata,outdata;
  714.    
  715.    if(!dalloc(fh)){
  716.       OUTOFMEM;
  717.       return NULL;
  718.    }
  719.    fh->cfsfh.objtype = XPKOBJECT;
  720.    fh->cfsfh.mode = MODE_OLDFILE;
  721.    fh->cfsfh.xfh = xfh;
  722.    fh->cfsfh.f = &Xpkfunc;
  723.    /* fh->cfsfh.filename and fh->cfsfh.parent NULL by default. */
  724.    
  725.    if(!(fh->unpackedxpk=newunpackedxpk())){
  726.       OUTOFMEM;
  727.       dfree(fh);
  728.       return NULL;
  729.    }
  730.    
  731.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  732.    inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
  733.    indata.glob=glob;
  734.    indata.fh=fh;
  735.    inhook.h_Data = &indata;
  736.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  737.    outhook.h_SubEntry = (ULONG (*)())xpkunpackout;
  738.    outdata.glob=glob;
  739.    outdata.fh=fh;
  740.    outhook.h_Data = &outdata;
  741.  
  742.    /* Get length of file, if possible. */
  743.    inlen = xFileSizeXfh( glob, xfh );
  744.  
  745.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  746.    res = MyXpkUnpackTags( glob,
  747.             XPK_InHook, &inhook,
  748.             XPK_OutHook, &outhook,
  749.             XPK_Password, glob->xpkpassword,
  750.             TAGIF(inlen!=-1L,XPK_InLen), inlen,
  751.             TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  752.             TAG_DONE
  753.          );
  754.     debug(("XpkUnPack() returned: %ld\n",res));
  755.    FreeXpkInBuf(fh);
  756.    FreeXpkOutBuf(fh);
  757.    
  758.    if(res != XPKERR_OK){
  759.       if(!glob->ioerr){
  760.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  761.          /* should perhaps open a requester to inform the user of */
  762.          /* the problem (showing an XpkErr)? */
  763.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  764.       }
  765.       killunpackedxpk(fh->unpackedxpk);
  766.       dfree(fh);
  767.       return NULL;
  768.    }
  769.    if(fh->unpackedxpk->first)
  770.       fh->filelen = fh->unpackedxpk->last->abspos 
  771.                   + fh->unpackedxpk->last->size; /* else 0 by default. */
  772.    return fh;
  773. }
  774.  
  775.  
  776. /* Perform a XpkExamine() on an UFS file handle. */
  777. BOOL XpkExamine_FH( glb glob, struct FileHandle *xfh, struct XpkFib *fib ){
  778.    LONG res;
  779.    LONG inlen;
  780.    struct XpkFH *fh;
  781.    struct Hook inhook;
  782.    struct xpkhookdata indata;
  783.    
  784.    if(!dalloc(fh)){ /* NOTE: NOT a real xpkfilehandle (only InBuf is used). */
  785.       OUTOFMEM;
  786.       return FALSE;
  787.    }
  788.    fh->cfsfh.xfh = xfh;
  789.  
  790.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  791.    inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
  792.     indata.glob=glob;
  793.     indata.fh=fh;
  794.    inhook.h_Data = &indata;
  795.  
  796.    /* Get length of file, if possible. */
  797.    inlen = xFileSizeXfh( glob, xfh );
  798.    
  799.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  800.    res = MyXpkExamine( glob, fib,
  801.             XPK_InHook,&inhook,
  802.             TAGIF(inlen!=-1L,XPK_InLen), inlen,
  803.             TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  804.             TAG_DONE
  805.          );
  806.     debug(("XpkExamine() returned: %ld\n",res));
  807.    FreeXpkInBuf(fh);
  808.    dfree(fh);
  809.       /* Need a better error message here. */
  810.    if( res && !glob->ioerr ) glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  811.     return (BOOL)( res==XPKERR_OK );
  812. }    
  813.  
  814.  
  815. /* This is the function that does the actual compression (using xpk) from
  816.  * one file handle to another.
  817.  */
  818. static BOOL XpkPackFH2FH(glb glob, struct FileHandle *srcxfh,
  819.                          LONG inlen, struct FileHandle *dstxfh){
  820.    struct XpkFH *srcxpkfh,*dstxpkfh;  /* NOTE: these are FAKE/invalid. */
  821.    LONG res;
  822.    LONG outlen;                     /* Dummy variable. */
  823.    struct Hook inhook,outhook;
  824.    struct xpkhookdata indata,outdata;
  825.    
  826.    /* Create the two fake XpkFH filehandles for the hooks. */
  827.    if(!dalloc(srcxpkfh)){
  828.       OUTOFMEM;
  829.       return FALSE;
  830.    }
  831.    if(!dalloc(dstxpkfh)){
  832.       OUTOFMEM;
  833.       dfree(srcxpkfh);
  834.       return FALSE;
  835.    }
  836.    srcxpkfh->cfsfh.xfh = srcxfh;   /* Buffer pointers NULL by default. */
  837.    dstxpkfh->cfsfh.xfh = dstxfh;   /* Buffer pointers NULL by default. */
  838.    
  839.    /* Set up hooks. */
  840.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  841.    inhook.h_SubEntry = (ULONG (*)())xpkpackin;
  842.    indata.glob=glob;
  843.    indata.fh=srcxpkfh;
  844.    inhook.h_Data = &indata;
  845.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  846.    outhook.h_SubEntry = (ULONG (*)())xpkpackout;
  847.    outdata.glob=glob;
  848.    outdata.fh=dstxpkfh;
  849.    outhook.h_Data = &outdata;
  850.  
  851.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  852.    res = MyXpkPackTags( glob,
  853.       XPK_InHook,&inhook,
  854.       XPK_OutHook,&outhook,
  855.       XPK_InLen,inlen,
  856.       XPK_PackMethod,glob->packmode,
  857.       XPK_StepDown,glob->stepdown,
  858.       XPK_Password,glob->xpkpassword,
  859.       XPK_GetOutLen,&outlen, /* NOTE: not used, buf xpk.doc says needed. */
  860.       TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  861.       TAG_DONE
  862.     );
  863.     debug(("XpkPack() returned: %ld\n",res));
  864.    
  865.    FreeXpkInBuf(srcxpkfh);
  866.    FreeXpkOutBuf(dstxpkfh);
  867.    dfree(srcxpkfh);
  868.    dfree(dstxpkfh);
  869.  
  870.    if(res != XPKERR_OK){
  871.       if(!glob->ioerr){
  872.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  873.          /* should perhaps open a requester to inform the user of */
  874.          /* the problem (showing an XpkErr)? */
  875.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  876.       }
  877.       return FALSE;
  878.    }
  879.    return TRUE;
  880. }
  881.  
  882.  
  883. /* This is the function that does the actual compression (using xpk) from
  884.  * one file handle to another.
  885.  */
  886. static BOOL XpkUnPackFH2FH(glb glob, struct FileHandle *srcxfh,
  887.                          LONG inlen, struct FileHandle *dstxfh){
  888.    struct XpkFH *srcxpkfh,*dstxpkfh;  /* NOTE: these are FAKE/invalid. */
  889.    LONG res;
  890.    struct Hook inhook,outhook;
  891.    struct xpkhookdata indata,outdata;
  892.    
  893.    /* Create the two fake XpkFH filehandles for the hooks. */
  894.    if(!dalloc(srcxpkfh)){
  895.       OUTOFMEM;
  896.       return FALSE;
  897.    }
  898.    if(!dalloc(dstxpkfh)){
  899.       OUTOFMEM;
  900.       dfree(srcxpkfh);
  901.       return FALSE;
  902.    }
  903.    srcxpkfh->cfsfh.xfh = srcxfh;   /* Buffer pointers NULL by default. */
  904.    dstxpkfh->cfsfh.xfh = dstxfh;   /* Buffer pointers NULL by default. */
  905.    
  906.    /* Set up hooks. */
  907.    inhook.h_Entry = (ULONG (*)())DoXpkHook;
  908.    inhook.h_SubEntry = (ULONG (*)())xpkpackin;
  909.    indata.glob=glob;
  910.    indata.fh=srcxpkfh;
  911.    inhook.h_Data = &indata;
  912.    outhook.h_Entry = (ULONG (*)())DoXpkHook;
  913.    outhook.h_SubEntry = (ULONG (*)())xpkpackout;
  914.    outdata.glob=glob;
  915.    outdata.fh=dstxpkfh;
  916.    outhook.h_Data = &outdata;
  917.  
  918.    glob->ioerr = 0L;          /* Set by hookfuncs if adequate. */
  919.    res = MyXpkUnpackTags( glob,
  920.       XPK_InHook,&inhook,
  921.       XPK_OutHook,&outhook,
  922.       XPK_InLen,inlen,
  923.       XPK_Password,glob->xpkpassword,
  924.       TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
  925.       TAG_DONE
  926.     );
  927.    debug(("XpkUnPack() returned: %ld\n",res));
  928.    
  929.    FreeXpkInBuf(srcxpkfh);
  930.    FreeXpkOutBuf(dstxpkfh);
  931.    dfree(srcxpkfh);
  932.    dfree(dstxpkfh);
  933.  
  934.    if(res != XPKERR_OK){
  935.       if(!glob->ioerr){
  936.          /* ToDo: Since no adequate AmigaDOS error code exists, we */
  937.          /* should perhaps open a requester to inform the user of */
  938.          /* the problem (showing an XpkErr)? */
  939.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;  /* More likely out of memory. */
  940.       }
  941.       return FALSE;
  942.    }
  943.    return TRUE;
  944. }
  945.  
  946.  
  947. /* NOTE BIEN: This function preserves the lock! */
  948. struct XpkFH *XpkOpenOldFileFromCopyOfLock( glb glob, struct XpkLock *lock ){
  949.    struct FileHandle *xfh;
  950.    struct XpkFH *fh;
  951.    
  952.    if(!(xfh = xOpenFromCopyOfLock(glob, lock->cfslock.xlock))){
  953.       debug(("Unable to xOpenFromLock(): %ld.\n",glob->ioerr));
  954.       return NULL;
  955.    }
  956.    fh = XpkOpenOldFile( glob, xfh );
  957.    if(!fh){
  958.       LONG saveioerr = glob->ioerr;
  959.       xClose(glob,xfh);
  960.       glob->ioerr = saveioerr;
  961.    }
  962.    return fh;
  963. }
  964.  
  965.  
  966. /* Check if a given filehandle belongs to an Xpk file. glob->ioerr
  967.  * set and FALSE returned in case of error.
  968.  */
  969.  
  970. BOOL IsXpkFile( glb glob, struct FileHandle *xfh ){
  971.    struct XpkFib fib;
  972.    
  973.    if( !XpkExamine_FH(glob, xfh, &fib) ){
  974.       debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
  975.       return FALSE;
  976.    }else if( fib.Type == XPKTYPE_PACKED ){
  977.       return TRUE;
  978.    }else{
  979.       glob->ioerr = 0L;
  980.       return FALSE;
  981.    }
  982. }
  983.  
  984.  
  985. /* This is the main entry to the automatic compression, and is the
  986.  * function passed to TransFormFile().
  987.  */
  988. BOOL PackFile2File(glb glob, struct FileHandle *srcxfh,
  989.                    struct FileHandle *dstxfh, void *dummy){
  990.    LONG srcsize;
  991.    
  992.    srcsize = xGetFileSize(glob, srcxfh);
  993.    if(srcsize == -1L){
  994.       debug(("Error: PackFile2File(): Could not obtain file length.\n"));
  995.       return FALSE;
  996.    }
  997.    return XpkPackFH2FH(glob, srcxfh, srcsize, dstxfh);
  998. }
  999.  
  1000.  
  1001. /* This function is passed to TransFormFile() to unpack a file to another
  1002.  * file (to handle Write() to an Xpk file).
  1003.  */
  1004. BOOL UnPackFile2File(glb glob, struct FileHandle *srcxfh,
  1005.                      struct FileHandle *dstxfh, void *dummy){
  1006.    LONG srcsize;
  1007.    
  1008.    srcsize = xGetFileSize(glob, srcxfh);
  1009.    if(srcsize == -1L){
  1010.       debug(("Error: UnPackFile2File(): Could not obtain file length.\n"));
  1011.       return FALSE;
  1012.    }
  1013.    return XpkUnPackFH2FH(glob, srcxfh, srcsize, dstxfh);
  1014. }
  1015.  
  1016.  
  1017. /*------------------------------------------------------------------------*
  1018.  * Virtual functions for Open(), Read(), Lock() etc.
  1019.  */
  1020.  
  1021. LONG Xpk_Read( glb glob, struct XpkFH *fh, UBYTE *buf, LONG len ){
  1022.  
  1023.    if( fh->unpackedxpk->currentpos+len > fh->filelen )
  1024.       len = fh->filelen - fh->unpackedxpk->currentpos;
  1025.    if( len <= 0 ) return 0L;
  1026.    
  1027.    if(!readunpackedxpk(fh->unpackedxpk, buf, len )){
  1028.       return -1L;
  1029.    }
  1030.    return len;
  1031. }
  1032.  
  1033.  
  1034. LONG Xpk_Seek( glb glob, struct XpkFH *fh, LONG pos, LONG offset ){
  1035.     LONG abspos;
  1036.     LONG oldpos = fh->unpackedxpk->currentpos;
  1037.    
  1038.    if( offset != OFFSET_BEGINNING &&
  1039.        offset != OFFSET_CURRENT   &&
  1040.        offset != OFFSET_END ){
  1041.       debug(("Error: Xpk: Bad offset value for Seek(): %ld\n",offset));
  1042.       glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  1043.       return -1L;
  1044.    }
  1045.    abspos = abs_seek_pos( fh->unpackedxpk->currentpos, fh->filelen, pos, offset );
  1046.    if( abspos < 0 || abspos > fh->filelen ){
  1047.       debug(("Error: Xpk: Bad abs. pos. in Seek(): %ld\n",abspos));
  1048.       glob->ioerr = ERROR_SEEK_ERROR;
  1049.       return -1L;
  1050.    }
  1051.     debug(("XpkSeek(): fh=%lx, pos=%ld, offset=%ld, abspos=%ld\n",fh,pos,offset,abspos));
  1052.    seekunpackedxpk(fh->unpackedxpk,abspos);
  1053.    
  1054.    return oldpos;
  1055. }
  1056.  
  1057.  
  1058. BOOL Xpk_Close( glb glob, struct XpkFH *fh ){
  1059.   BOOL res;
  1060.    
  1061.   if(!fh->cfsfh.xfh){
  1062.     debug(("Xpk_Close(): Bad fh.\n"));
  1063.     glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  1064.     return FALSE;
  1065.   }
  1066.   res = xClose( glob, fh->cfsfh.xfh );
  1067.   if( res ){
  1068.     killunpackedxpk(fh->unpackedxpk);
  1069.     XObjUnStuffFH(glob, &fh->cfsfh);
  1070.     dfree(fh);
  1071.   }else{
  1072.     debug(("ERROR: Xpk: xClose() returned false - mem not freed.\n"));
  1073.   }
  1074.   return res;
  1075. }
  1076.  
  1077.  
  1078. /* Xpk_Write() needs to do some magic to prepare the file for writing. The
  1079.  * idea is to replace the file (on disk) with the unpacked data, then make
  1080.  * the file handle look like a CFSFH.
  1081.  *
  1082.  * One possibility would be to write the data in memory. However, since
  1083.  * the file could have changed since this Open(), it's safer to
  1084.  * uncompress the file again.
  1085.  */
  1086. LONG Xpk_Write(glb glob, struct XpkFH *fh, UBYTE *buf, LONG len){
  1087.   BOOL res;
  1088.   char *filename = fh->cfsfh.filename;
  1089.   struct FileLock *xlock = fh->cfsfh.parent->xlock;
  1090.   struct FileHandle *xfh = fh->cfsfh.xfh;
  1091.   LONG currentpos;
  1092.  
  1093.   if(!glob->allowappend){
  1094.     debug(("Xpk_Write(): Appendmode not set - failing.\n"));
  1095.     glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  1096.     return -1L;
  1097.   }
  1098.   if(!xfh){
  1099.     debug(("XpkWrite(): Bad fh.\n"));
  1100.     glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  1101.     return -1L;
  1102.   }
  1103.   if(!filename){
  1104.     debug(("Error: Xpk_Write(): no name info.\n"));
  1105.     glob->ioerr = ERROR_ACTION_NOT_KNOWN;
  1106.     return -1L;
  1107.   }
  1108.   debug(("Attempting to uncompress file %s.\n",filename));
  1109.   if(!xChangeMode(glob, CHANGE_FH, xfh, MODE_NEWFILE)){
  1110.     debug(("Error: Xpk_Write(): xChangeMode(): %ld.\n",glob->ioerr));
  1111.     return -1L;
  1112.   }
  1113.   if(-1L == xSeek(glob, xfh, 0L, OFFSET_BEGINNING)){
  1114.     debug(("Error: Xpk_Write(): Could not seek to start: %ld.\n",glob->ioerr));
  1115.     return -1L;
  1116.   }
  1117.   res = TransformXFH(glob, xfh, xlock, filename, UnPackFile2File, NULL);
  1118.   debug(("TransformFile() returned: %ld.\n",res));
  1119.   fh->cfsfh.xfh = xfh = NULL;   /* The handle was closed by TransformFile(). */
  1120.   if(!res){
  1121.     SAVEIOERR;
  1122.     /* Bad luck! The uncompress didn't work. Since our xfh is gone, we'll
  1123.      * have to do some magic to save as much as possible.
  1124.      */
  1125.     if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
  1126.       debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
  1127.       /* Nothing to do about it, really... */
  1128.     }
  1129.     RESTIOERR;
  1130.     return -1L;
  1131.   }
  1132.   if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
  1133.     debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
  1134.     /* Nothing to do about it, really... */
  1135.     return -1L;
  1136.   }
  1137.   fh->cfsfh.xfh = xfh;
  1138.   currentpos = fh->unpackedxpk->currentpos;
  1139.   killunpackedxpk(fh->unpackedxpk);
  1140.   if(!glob->compressreadwrite) XObjUnStuffFH(glob, &fh->cfsfh);
  1141.   XObjStealXpkFH(glob, &fh->cfsfh);
  1142.   if(-1L == xSeek(glob, xfh, currentpos, OFFSET_BEGINNING)){
  1143.     debug(("Error: Xpk_Write(): Could not seek to right pos: %ld.\n",glob->ioerr));
  1144.     return -1L;
  1145.   }else{
  1146.     return XObjWrite(glob, &fh->cfsfh, buf, len);
  1147.   }
  1148. }
  1149.  
  1150.  
  1151. struct XpkLock *XpkMakeLock( glb glob, struct FileLock *xlock, LONG mode ){
  1152.     struct XpkLock *newlock;
  1153.     
  1154.     if( !dalloc(newlock) ){
  1155.         OUTOFMEM;
  1156.         return NULL;
  1157.     }
  1158.     newlock->cfslock.objtype = XPKOBJECT;
  1159.     newlock->cfslock.mode = mode;
  1160.     newlock->cfslock.xlock = xlock;
  1161.     newlock->cfslock.f = &Xpkfunc;
  1162.    newlock->cfslock.refcount = 0;    /* NOTE: NOT used for XpkObject's. */
  1163.     return newlock;
  1164. }
  1165.  
  1166.  
  1167. struct XpkLock *XpkDupLock( glb glob, struct XpkLock *lock ){
  1168.    struct XpkLock *newlock;
  1169.  
  1170.    /* XPKOBJECT locks have their xLocks xDupLock'ed, and the rest of
  1171.     * the fields are just copied vanilla.
  1172.     */
  1173.    if( !dalloc(newlock) ){
  1174.       OUTOFMEM;
  1175.       return 0L;
  1176.    }
  1177.    *newlock = *lock;
  1178.    newlock->cfslock.refcount = 0L;   /* Again: refcount is not used. */
  1179.    if( !(newlock->cfslock.xlock = xDupLock(glob, lock->cfslock.xlock)) ){
  1180.       dfree(newlock);
  1181.       return 0L;
  1182.    }
  1183.    return newlock;   
  1184. }
  1185.  
  1186.  
  1187. /* NOTE BIEN: The parent lock is a XOBJECT, not a XPKOBJECT! */
  1188. struct CFSLock *XpkParentDir( glb glob, struct XpkLock *lock ){
  1189.     struct FileLock *xlock;
  1190.     struct CFSLock *newlock;
  1191.     
  1192.     if( !(xlock = xParentDir(glob, lock->cfslock.xlock)) ){
  1193.         return 0L;
  1194.     }
  1195.     newlock = XObjMakeLock( glob, xlock, ACCESS_READ );
  1196.     if( !newlock ){
  1197.         LONG saveioerr = glob->ioerr;
  1198.         xUnLock(glob, xlock);
  1199.         glob->ioerr = saveioerr;
  1200.     }
  1201.     return newlock;
  1202. }
  1203.  
  1204.  
  1205. BOOL XpkUnLock( glb glob, struct XpkLock *lock ){
  1206.     BOOL err;
  1207.  
  1208.    if(lock->cfslock.refcount){
  1209.       /* This should NOT have happened! */
  1210.       debug(("\n\n***PANIC***: XpkUnLock: Nonzero refcount in lock (%ld).\n",lock->cfslock.refcount));
  1211.       return DOSFALSE;
  1212.    }
  1213.     err = xUnLock(glob, lock->cfslock.xlock);
  1214.       
  1215.     /* Now, what if the UnLock fails? I guess it's best to return FALSE
  1216.      * and let the lock live.
  1217.      */
  1218.     if(!err) return DOSFALSE;
  1219.     dfree(lock);
  1220.     return DOSTRUE;
  1221. }
  1222.  
  1223.  
  1224. BOOL XpkSameLock(glb glob, struct XpkLock *l1, struct XpkLock *l2 ){
  1225.     return xSameLock( glob, l1->cfslock.xlock, l2->cfslock.xlock ) == LOCK_SAME;
  1226. }
  1227.  
  1228.  
  1229. BOOL XpkObjExamine( glb glob, struct XpkLock *lock, struct FileInfoBlock *fib ){
  1230.     BOOL err;
  1231.     struct FileHandle *xfh;
  1232.     
  1233.     debug(("XpkObjExamine(): "));
  1234.     err = xExamine(glob, lock->cfslock.xlock, fib);
  1235.     debug(("%ld,'%s'\n",err,fib->fib_FileName));
  1236.     if( !err ) return err;
  1237.     xfh = xOpenFromCopyOfLock( glob, lock->cfslock.xlock );
  1238.     if( !xfh ){
  1239.         debug(("Error: XpkExamine(): Cannot open file from lock %lx.\n",lock));
  1240.         return DOSFALSE;
  1241.     }
  1242.     err = XpkModifyFIB( glob, lock, fib, xfh );
  1243.     if( !err ){
  1244.         LONG saveioerr;
  1245.  
  1246.         saveioerr = glob->ioerr;
  1247.         xClose( glob, xfh );
  1248.         glob->ioerr = saveioerr;
  1249.         return DOSFALSE;
  1250.     }else{
  1251.         xClose( glob, xfh );
  1252.         return DOSTRUE;
  1253.     }
  1254. }
  1255.  
  1256.  
  1257. /* XpkModifyFIB() has to fix the length of the file. */
  1258. BOOL XpkModifyFIB( glb glob, struct XpkLock *lock,struct FileInfoBlock *fib, struct FileHandle *xfh ){
  1259.    struct XpkFib xpkfib;
  1260.    
  1261.    if( !XpkExamine_FH(glob, xfh, &xpkfib) ){
  1262.       debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
  1263.       return FALSE;
  1264.    }
  1265.    fib->fib_Size = xpkfib.ULen;
  1266.    /* ToDo: Should NOT have fixed block size (look at UFS). */
  1267.    fib->fib_NumBlocks = (fib->fib_Size+BLOCKSIZE-1) / BLOCKSIZE;
  1268.  
  1269.    return DOSTRUE;
  1270. }
  1271.  
  1272.  
  1273. /*------------------------------------------------------------------------*
  1274.  * Initialise and cleanup functions.
  1275.  */
  1276.  
  1277. BOOL InitXpk( glb glob ){
  1278.   
  1279.   if(!(glob->XpkBase = OpenLibrary("xpkmaster.library",0L)))
  1280.       return FALSE;
  1281.    XpkBase = glob->XpkBase;
  1282.    if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
  1283.       glob->xpkport = NULL;
  1284.    }else{
  1285.       if(!(glob->xpkport=CreatePort("CFS port for KS1.3 Xpk-calls.",0L))){
  1286.          CloseLibrary(glob->XpkBase);
  1287.          debug(("Error creating xpk message port.\n"));
  1288.          return FALSE;
  1289.       }
  1290.    }
  1291.  
  1292.    return TRUE;
  1293. }
  1294.  
  1295.  
  1296. void CleanupXpk( glb glob ){
  1297.    
  1298.    if( glob->xpkport ) DeletePort( glob->xpkport );
  1299.    if( glob->XpkBase ) CloseLibrary( XpkBase );
  1300. }
  1301.  
  1302.  
  1303. /* End of xpk.c */
  1304.