home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / System / XADmaster / xad_dev / Sources / tools / xadUnTar.c < prev   
Encoding:
C/C++ Source or Header  |  2001-04-01  |  22.2 KB  |  788 lines

  1. #define NAME         "xadUnTar"
  2. #define DISTRIBUTION "(Freeware) "
  3. #define REVISION     "2"
  4. #define DATE         "31.03.2001"
  5.  
  6. /* Programmheader
  7.  
  8.     Name:        xadUnTar
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    dearchives tar archives (also gzipped, bzipped, compressed)
  12.     Compileropts:    -
  13.     Linkeropts:    -gsi -l amiga
  14.  
  15.  1.0   06.11.00 : first version, based on xadUnFile.c
  16.  1.1   17.12.00 : added fix for octtonum
  17.  1.2   31.03.01 : handles empty file correct now
  18. */
  19.  
  20. #include <proto/xadmaster.h>
  21. #include <proto/exec.h>
  22. #include <proto/dos.h>
  23. #include <exec/memory.h>
  24. #include <dos/dosasl.h>
  25. #include <utility/hooks.h>
  26. #include "SDI_version.h"
  27. #include "SDI_compiler.h"
  28. #define SDI_TO_ANSI
  29. #include "SDI_ASM_STD_protos.h"
  30.  
  31. struct xadMasterBase *    xadMasterBase = 0;
  32. struct DosLibrary *     DOSBase = 0;
  33. struct ExecBase *     SysBase  = 0;
  34.  
  35. #define MINPRINTSIZE    51200    /* 50KB */
  36. #define NAMEBUFSIZE    512
  37. #define PATBUFSIZE    (NAMEBUFSIZE*2+10)
  38.  
  39. #define PARAM    "FROM/A,DEST=DESTDIR,PASSWORD/K,FILE/M,"    \
  40.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  41.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  42.         "OW=OVERWRITE/S,NA=NOABS/S,ND=NODATE/S,"    \
  43.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  44.         "NT=NOTREE/S"
  45.  
  46. #define OPTIONS \
  47.   "FROM       The input archive file (no patterns allowed)\n"        \
  48.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  49.   "PASSWORD   A password for encrypted archives\n"            \
  50.   "FILE       Filename(s) (with patterns) to be extracted\n"        \
  51.   "NAMESIZE   Names with more characters result in rename request\n"    \
  52.   "FFS=OFS    Sets NAMESIZE to 30\n"                    \
  53.   "SFS        Sets NAMESIZE to 100\n"                    \
  54.   "INFO       Shows archive information without extracting\n"        \
  55.   "QUIET      Turns of progress report and user interaction\n"        \
  56.   "ASKMAKEDIR You get asked before a directory is created\n"        \
  57.   "OVERWRITE  Files are overwritten without asking\n"            \
  58.   "NOABS      Do not extract absolute path name parts\n"        \
  59.   "NODATE     Creation date information gets not extracted\n"        \
  60.   "NOEXTERN   Turns off usage of external clients\n"            \
  61.   "NOKILLPART Do not delete partial or corrupt output files.\n"        \
  62.   "NOPROT     Protection information gets not extracted\n"        \
  63.   "NOTREE     Files are extracted without subdirectories\n"
  64.  
  65. struct xHookArgs {
  66.   STRPTR name;
  67.   ULONG size;
  68.   ULONG flags;
  69.   ULONG lastprint;
  70. };
  71.  
  72. struct Args {
  73.   STRPTR   from;
  74.   STRPTR   destdir;
  75.   STRPTR   password;
  76.   STRPTR * file;
  77.   LONG *   namesize;
  78.   ULONG    ffs;
  79.   ULONG       sfs;
  80.   ULONG    info;
  81.   ULONG    quiet;
  82.   ULONG    askmakedir;
  83.   ULONG    overwrite;
  84.   ULONG    noabs;
  85.   ULONG    nodate;
  86.   ULONG    noextern;
  87.   ULONG       nokillpart;
  88.   ULONG    noprot;
  89.   ULONG    notree;
  90. };
  91.  
  92. struct TarHeader
  93. {                /* byte offset */
  94.   UBYTE th_Name[100];        /*   0 */
  95.   UBYTE th_Mode[8];        /* 100 */
  96.   UBYTE th_UserID[8];        /* 108 */
  97.   UBYTE th_GroupID[8];        /* 116 */
  98.   UBYTE th_Size[12];        /* 124 */
  99.   UBYTE th_MTime[12];        /* 136 */
  100.   UBYTE th_Checksum[8];     /* 148 */
  101.   UBYTE th_Typeflag;        /* 156 */
  102.   UBYTE th_LinkName[100];    /* 157 */
  103.   UBYTE th_Magic[6];        /* 257 */
  104.   UBYTE th_Version[2];        /* 263 */
  105.   UBYTE th_UserName[32];    /* 265 */
  106.   UBYTE th_GroupName[32];    /* 297 */
  107.   UBYTE th_DevMajor[8];     /* 329 */
  108.   UBYTE th_DevMinor[8];     /* 337 */
  109.   UBYTE th_Prefix[155];     /* 345 */
  110.   UBYTE th_Pad[12];        /* 500 */
  111. };
  112.  
  113. struct TarBlockInfo {
  114.   struct Args *        Args;
  115.   struct xadArchiveInfo *ArchiveInfo;
  116.   UBYTE            Block[512];
  117.   struct TarHeader    Header;
  118.   ULONG            CurSize;
  119.   ULONG            NumFile;
  120.   ULONG            NumDir;
  121.   LONG            NeedToSkip; /* bytes */
  122.   LONG            NeedToSave; /* bytes */
  123.   struct Hook        Hook;
  124.   struct xHookArgs    HookArgs;
  125.   UBYTE                 Filename[NAMEBUFSIZE];
  126. };
  127.  
  128. /* Values used in Typeflag field.  */
  129. #define TF_FILE     '0'  /* Regular file */
  130. #define TF_AFILE    '\0' /* Regular file */
  131. #define TF_LINK     '1'  /* Link */
  132. #define TF_SYM        '2'  /* Reserved - but GNU tar uses this for links... */
  133. #define TF_CHAR     '3'  /* Character special */
  134. #define TF_BLOCK    '4'  /* Block special */
  135. #define TF_DIR        '5'  /* Drawer */
  136. #define TF_FIFO     '6'  /* FIFO special */
  137. #define TF_CONT     '7'  /* Reserved */
  138.  
  139. ASM(ULONG) progrhook(REG(a0, struct Hook *), REG(a1, struct xadProgressInfo *));
  140. ASM(ULONG) workhook(REG(a0, struct Hook *), REG(a1, struct xadHookParam *));
  141. static ULONG octtonum(STRPTR oct, LONG width, LONG *ok);
  142. static BOOL checktarsum(struct TarHeader *th);
  143. static LONG handleblock(struct TarBlockInfo *t);
  144. static void ShowProt(ULONG i);
  145. static LONG CheckNameSize(STRPTR name, ULONG size);
  146. static LONG CheckName(STRPTR *pat, STRPTR name);
  147.  
  148. ULONG start(void)
  149. {
  150.   ULONG ret = RETURN_FAIL;
  151.   struct DosLibrary *dosbase;
  152.  
  153.   SysBase = (*((struct ExecBase **) 4));
  154.   { /* test for WB and reply startup-message */
  155.     struct Process *task;
  156.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  157.     {
  158.       WaitPort(&task->pr_MsgPort);
  159.       Forbid();
  160.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  161.       return RETURN_FAIL;
  162.     }
  163.   }
  164.  
  165.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  166.   {
  167.     LONG err = 0;
  168.     struct xadMasterBase *xadmasterbase;
  169.  
  170.     DOSBase = dosbase;
  171.     if((xadmasterbase = (struct xadMasterBase *)
  172.     OpenLibrary("xadmaster.library", 9)))
  173.     {
  174.       struct Args args;
  175.       struct RDArgs *rda;
  176.       
  177.       memset(&args, 0, sizeof(struct Args));
  178.       xadMasterBase = xadmasterbase;
  179.  
  180.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  181.       {
  182.         rda->RDA_ExtHelp = OPTIONS;
  183.  
  184.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  185.         {
  186.           LONG namesize = 0;
  187.  
  188.           if(args.namesize && *args.namesize > 0)
  189.             namesize = *args.namesize;
  190.           else if(args.ffs)
  191.             namesize = 30;
  192.           else if(args.sfs)
  193.             namesize = 100;
  194.       args.namesize = &namesize;
  195.  
  196.       if(args.destdir || args.info)
  197.       {
  198.         struct xadArchiveInfo *ai;
  199.  
  200.         if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  201.         {
  202.           struct Hook outhook;
  203.           struct xadFileInfo *fi = 0;
  204.  
  205.           ret = 0;
  206.  
  207.           memset(&outhook, 0, sizeof(struct Hook));
  208.           outhook.h_Entry = (ULONG (*)()) workhook;
  209.           outhook.h_Data = &args;
  210.  
  211.           if(!(err = xadGetInfo(ai, XAD_INFILENAME, args.from, XAD_NOEXTERN, args.noextern,
  212.           args.password ? XAD_PASSWORD : TAG_IGNORE, args.password, TAG_DONE)))
  213.           {
  214.             fi = ai->xai_FileInfo;
  215.  
  216.             if(fi && ai->xai_Client->xc_Identifier != XADCID_TAR)
  217.                   err = xadFileUnArc(ai, XAD_OUTHOOK, &outhook, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE);
  218.                 else
  219.                   fi = 0;
  220.                 xadFreeInfo(ai);
  221.               }
  222.               
  223.           if(!fi) /* above did not work. Try as normal archive (plain tar). */
  224.           {
  225.             if(!(err = xadGetHookAccess(ai, XAD_OUTHOOK, &outhook, XAD_INFILENAME, args.from, TAG_DONE)))
  226.             {
  227.               err = xadHookAccess(XADAC_COPY, ai->xai_InSize, 0, ai);
  228.                   xadFreeHookAccess(ai, err ? XAD_WASERROR : TAG_DONE, err, TAG_DONE);
  229.             }
  230.           }
  231.  
  232.           xadFreeObjectA(ai, 0);
  233.             } /* xadAllocObject */
  234.           }
  235.           else
  236.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  237.  
  238.           FreeArgs(rda);
  239.         } /* ReadArgs */
  240.         FreeDosObject(DOS_RDARGS, rda);
  241.       } /* AllocDosObject */
  242.  
  243.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  244.         SetIoErr(ERROR_BREAK);
  245.  
  246.       if(!args.quiet)
  247.       {
  248.         if(err)
  249.       Printf("\r\033[KAn error occured: %s\n", xadGetErrorText(err));
  250.         else if(ret)
  251.           PrintFault(IoErr(), 0);
  252.       }
  253.  
  254.       CloseLibrary((struct Library *) xadmasterbase);
  255.     } /* OpenLibrary xadmaster */
  256.     else
  257.       Printf("Could not open xadmaster.library\n");
  258.     CloseLibrary((struct Library *) dosbase);
  259.   } /* OpenLibrary dos */
  260.   return ret;
  261. }
  262.  
  263. static ULONG octtonum(STRPTR oct, LONG width, LONG *ok)
  264. {
  265.   ULONG i = 0;
  266.  
  267.   while(*oct == ' ' && width--)
  268.     ++oct;
  269.  
  270.   if(!*oct)
  271.     *ok = 0;
  272.   else
  273.   {
  274.     while(width-- && *oct >= '0' && *oct <= '7')
  275.      i = (i*8)+*(oct++)-'0';
  276.  
  277.     while(*oct == ' ' && width--)
  278.       ++oct;
  279.  
  280.     if(width > 0 && *oct)    /* an error, set error flag */
  281.       *ok = 0;
  282.   }
  283.  
  284.   return i;
  285. }
  286.  
  287. static BOOL checktarsum(struct TarHeader *th)
  288. {
  289.   LONG sc, i;
  290.   ULONG uc, checks;
  291.   
  292.   i = 1;
  293.   checks = octtonum(th->th_Checksum, 8, &i);
  294.   if(!i)
  295.     return 0;
  296.  
  297.   for(i = sc = uc = 0; i < 512; ++i)
  298.   {
  299.     sc += ((BYTE *) th)[i];
  300.     uc += ((UBYTE *) th)[i];
  301.   }
  302.   
  303.   for(i = 148; i < 156; ++i)
  304.   {
  305.     sc -= ((BYTE *) th)[i];
  306.     uc -= ((UBYTE *) th)[i];
  307.   }
  308.   sc += 8 * ' ';
  309.   uc += 8 * ' ';
  310.   
  311.   if(checks != uc && checks != (ULONG) sc)
  312.     return 0;
  313.   return 1;
  314. }
  315.  
  316. static void FinishFile(struct TarBlockInfo *t)
  317. {
  318.   struct DateStamp d;
  319.   LONG a, ok;
  320.  
  321.   if(!t->Args->nodate)
  322.   {
  323.     xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  324.     XAD_MAKELOCALDATE, 1, XAD_GETDATEDATESTAMP, &d, TAG_DONE);
  325.     SetFileDate(t->Filename, &d);
  326.   }
  327.   if(!t->Args->noprot)
  328.   {
  329.     xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok),
  330.     XAD_GETPROTAMIGA, &a, TAG_DONE);
  331.     SetProtection(t->Filename, a);
  332.   }
  333. }
  334.  
  335. static LONG handleblock(struct TarBlockInfo *t)
  336. {
  337.   LONG err = 0;
  338.  
  339.   if(t->CurSize != 512)
  340.   {
  341.     if(t->ArchiveInfo)
  342.     {
  343.       xadFreeHookAccess(t->ArchiveInfo, XAD_WASERROR, XADERR_INPUT, TAG_DONE);
  344.       xadFreeObjectA(t->ArchiveInfo, 0);
  345.       t->ArchiveInfo = 0;
  346.     }
  347.     if(!t->Args->info && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  348.     {
  349.       Printf("Processed");
  350.       if(t->NumFile)
  351.         Printf(" %ld file%s%s", t->NumFile, t->NumFile == 1 ? "" : "s", t->NumDir ? " and" : "");
  352.       if(t->NumDir)
  353.         Printf(" %ld director%s", t->NumDir, t->NumDir == 1 ? "y" : "ies");
  354.       if(!t->NumFile && !t->NumDir)
  355.         Printf(" nothing");
  356.       Printf(".\n");
  357.     }
  358.   }
  359.   else if(t->NeedToSkip)
  360.   {
  361.     if(t->NeedToSkip > 512)
  362.       t->NeedToSkip -= 512;
  363.     else
  364.       t->NeedToSkip = 0;
  365.   }
  366.   else if(t->NeedToSave)
  367.   {
  368.     if(t->NeedToSave > 512)
  369.     {
  370.       t->NeedToSave -= 512;
  371.       if((err = xadHookAccess(XADAC_WRITE, 512, t->Block, t->ArchiveInfo)))
  372.       {
  373.         xadFreeHookAccess(t->ArchiveInfo, XAD_WASERROR, err, TAG_DONE);
  374.         xadFreeObjectA(t->ArchiveInfo, 0);
  375.         t->NeedToSkip = t->NeedToSave;
  376.         t->NeedToSave = 0;
  377.         t->ArchiveInfo = 0;
  378.       }
  379.     }
  380.     else
  381.     {
  382.       err = xadHookAccess(XADAC_WRITE, t->NeedToSave, t->Block, t->ArchiveInfo);
  383.       xadFreeHookAccess(t->ArchiveInfo, err ? XAD_WASERROR : TAG_DONE, err, TAG_DONE);
  384.       xadFreeObjectA(t->ArchiveInfo, 0);
  385.       t->NeedToSave = 0;
  386.       t->ArchiveInfo = 0;
  387.       if(!err)
  388.         FinishFile(t);
  389.     }
  390.   }
  391.   else /* a file header block */
  392.   {
  393.     xadCopyMem(t->Block, &t->Header, 512);
  394.  
  395.     if(t->Header.th_Name[0])
  396.     {
  397.       LONG ok, a;
  398.  
  399.       t->HookArgs.lastprint = 0;
  400.       ok = checktarsum(&t->Header); /* check checksum and init ok */
  401.       t->HookArgs.size = octtonum(t->Header.th_Size, 12, &ok);
  402.  
  403.       if(ok && (t->Header.th_Typeflag == TF_FILE || t->Header.th_Typeflag == TF_AFILE || t->Header.th_Typeflag == TF_DIR ||
  404.       t->Header.th_Typeflag == TF_SYM || t->Header.th_Typeflag == TF_LINK))
  405.       {
  406.         a = strlen(t->Header.th_Name) + 1;
  407.         if(t->Header.th_Name[a-2] == '/')
  408.         {
  409.       if(t->Header.th_Typeflag == TF_AFILE || t->Header.th_Typeflag == TF_FILE || t->Header.th_Typeflag == TF_DIR)
  410.       {
  411.         t->Header.th_Name[--a-1] == 0;
  412.             t->Header.th_Typeflag = TF_DIR;
  413.           }
  414.         }
  415.         if(t->Args->info)
  416.         {
  417.       struct xadDate xd;
  418.  
  419.           xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  420.           XAD_MAKELOCALDATE, 1, XAD_GETDATEXADDATE, &xd, TAG_DONE);
  421.           xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok), XAD_GETPROTAMIGA, &a, TAG_DONE);
  422.  
  423.           if(!(t->NumFile + t->NumDir))
  424.         Printf("Size     Date       Time     Protection       Name\n");
  425.  
  426.       if(t->Header.th_Typeflag == TF_DIR)
  427.       {
  428.             Printf("   <dir>"); ++t->NumDir;
  429.           }
  430.           else
  431.           {
  432.             Printf("%8ld", t->HookArgs.size);
  433.             t->NeedToSkip = t->HookArgs.size;
  434.             ++t->NumFile;
  435.           }
  436.           Printf(" %02ld.%02ld.%04ld %02ld:%02ld:%02ld ", xd.xd_Day, xd.xd_Month, xd.xd_Year,
  437.           xd.xd_Hour, xd.xd_Minute, xd.xd_Second);
  438.       ShowProt(a);
  439.       Printf("%s\n", t->Args->notree ? FilePart(t->Header.th_Name) : t->Header.th_Name);
  440.           if(t->Header.th_LinkName[0])
  441.         Printf("link: %s\n", t->Header.th_LinkName);
  442.         }
  443.         else
  444.         {
  445.           if(!t->Args->file || CheckName(t->Args->file, t->Args->notree ? FilePart(t->Header.th_Name) : t->Header.th_Name))
  446.           {
  447.             CopyMem(t->Args->destdir, t->Filename, strlen(t->Args->destdir)+1);
  448.             if(t->Args->notree)
  449.               AddPart(t->Filename, FilePart(t->Header.th_Name), NAMEBUFSIZE);
  450.             else if(!t->Args->noabs)
  451.               AddPart(t->Filename, t->Header.th_Name, NAMEBUFSIZE);
  452.             else
  453.             {
  454.               STRPTR fname = t->Filename, f;
  455.  
  456.               if(*t->Args->destdir)
  457.               {
  458.         fname += strlen(t->Args->destdir)-1;
  459.                 if(*fname != ':' && *fname != '/')
  460.           *(++fname) = '/';
  461.         ++fname;
  462.           }
  463.           for(f = t->Header.th_Name; *f == '/' || *f == ':'; ++f)
  464.             ;
  465.           for(; *f; ++f)
  466.             *(fname++) = *f == ':' ? '/' : *f;
  467.           *fname = 0;
  468.         }
  469.             if(t->Header.th_Typeflag == TF_SYM || t->Header.th_Typeflag == TF_LINK)
  470.         {
  471.           if(!t->Args->quiet)
  472.             Printf("Skipped Link\n");
  473.         }
  474.             else if(t->Header.th_Typeflag == TF_DIR)
  475.             {
  476.               if(!t->Args->notree)
  477.           {
  478.             BPTR a;
  479.             LONG i = 0;
  480.             UBYTE r;
  481.             ++t->NumDir;
  482.                 while(t->Filename[i] && !err)
  483.             {
  484.                 for(;t->Filename[i] && t->Filename[i] != '/'; ++i)
  485.                     ;
  486.                 r = t->Filename[i];
  487.                 t->Filename[i] = 0;
  488.               if((a = Lock(t->Filename, SHARED_LOCK)))
  489.                   UnLock(a);
  490.               else if((a = CreateDir(t->Filename)))
  491.                     UnLock(a);
  492.                 else
  493.                     err = 1;
  494.                   t->Filename[i++] = r;
  495.             }
  496.             if(!t->Args->quiet)
  497.             {
  498.               if(err)
  499.                 Printf("failed to create directory '%s'\n", t->Filename);
  500.           else
  501.             Printf("Created directory   : %s\n", t->Filename);
  502.         }
  503.             if(!err)
  504.             {
  505.               struct DateStamp d;
  506.               LONG a;
  507.  
  508.               if(!t->Args->nodate)
  509.               {
  510.                 xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  511.                 XAD_MAKELOCALDATE, 1, XAD_GETDATEDATESTAMP, &d, TAG_DONE);
  512.                 SetFileDate(t->Filename, &d);
  513.               }
  514.               if(!t->Args->noprot)
  515.               {
  516.                 xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok),
  517.                 XAD_GETPROTAMIGA, &a, TAG_DONE);
  518.                 SetProtection(t->Filename, a);
  519.               }
  520.             }
  521.           }
  522.         }
  523.         else
  524.         {
  525.           t->NeedToSave = t->HookArgs.size;
  526.           ++t->NumFile;
  527.           if(*t->Args->namesize && CheckNameSize(FilePart(t->Filename), *t->Args->namesize))
  528.             err = XADERR_BREAK;
  529.           else if((t->ArchiveInfo = xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  530.           {
  531.         if((err = xadGetHookAccess(t->ArchiveInfo, XAD_OUTFILENAME, t->Filename,
  532.         XAD_MAKEDIRECTORY, !t->Args->askmakedir, XAD_OVERWRITE, t->Args->overwrite,
  533.             XAD_NOKILLPARTIAL, t->Args->nokillpart,  t->Args->quiet ? TAG_IGNORE :
  534.             XAD_PROGRESSHOOK, &t->Hook, TAG_DONE)))
  535.         {
  536.           xadFreeObjectA(t->ArchiveInfo, 0);
  537.           t->ArchiveInfo = 0;
  538.           if(err == XADERR_SKIP)
  539.           {
  540.             t->NeedToSkip = t->NeedToSave;
  541.             t->NeedToSave = 0;
  542.             err = 0;
  543.           }
  544.         }
  545.         else if(!t->NeedToSave)
  546.         {
  547.                   xadFreeHookAccess(t->ArchiveInfo, TAG_DONE);
  548.                   xadFreeObjectA(t->ArchiveInfo, 0);
  549.           t->ArchiveInfo = 0;
  550.                   FinishFile(t);
  551.         }
  552.           }
  553.           else
  554.             err = XADERR_NOMEMORY;
  555.         }
  556.           }
  557.           else if(t->Header.th_Typeflag == TF_AFILE || t->Header.th_Typeflag == TF_FILE)
  558.             t->NeedToSkip = t->HookArgs.size;
  559.         }
  560.       }
  561.       else
  562.       {
  563.         if(!(t->NumFile + t->NumDir))
  564.           Printf("This is not an Tar file\n");
  565.         err = XADERR_ILLEGALDATA;
  566.       }
  567.     }
  568.   }
  569.   return err;
  570. }
  571.  
  572. /* Because of SAS-err, this cannot be SAVEDS */
  573. ASM(ULONG) workhook(REG(a0, struct Hook *hook),
  574. REG(a1, struct xadHookParam *hp))
  575. {
  576.   ULONG err = 0;
  577.   /* This hook gets the data and instead of saving, it calls the handleblock()
  578.   function with 512 byte blocks (tar block size). It is an XAD output hook and
  579.   used by the main routine as output. The hook structure contains an pointer
  580.   to the argument information. output seeking is not supported. */
  581.  
  582.   switch(hp->xhp_Command)
  583.   {
  584.   case XADHC_WRITE:
  585.     {
  586.       ULONG i, j, k = 0;
  587.       struct TarBlockInfo *t = (struct TarBlockInfo *) hp->xhp_PrivatePtr;
  588.  
  589.       for(j = hp->xhp_BufferSize; j && !err; j -= i)
  590.       {
  591.         if((i = 512-t->CurSize) > j)
  592.           i = j;
  593.         xadCopyMem(((STRPTR)hp->xhp_BufferPtr)+k, t->Block+t->CurSize, i);
  594.         k += i; t->CurSize += i;
  595.         if(t->CurSize == 512)
  596.         {
  597.           err = handleblock(t);
  598.           t->CurSize = 0;
  599.         }
  600.       }
  601.       hp->xhp_DataPos += hp->xhp_BufferSize;
  602.     }
  603.     break;
  604.   case XADHC_INIT:
  605.     if(!(hp->xhp_PrivatePtr = xadAllocVec(sizeof(struct TarBlockInfo), MEMF_CLEAR)))
  606.       err = XADERR_NOMEMORY;
  607.     else
  608.     {
  609.       struct TarBlockInfo *t = (struct TarBlockInfo *) hp->xhp_PrivatePtr;
  610.  
  611.       t->Args = (struct Args *) hook->h_Data;
  612.       t->Hook.h_Entry = (ULONG (*)()) progrhook;
  613.       t->Hook.h_Data = &t->HookArgs;
  614.       t->HookArgs.name = t->Filename;
  615.     }
  616.     break;
  617.   case XADHC_FREE:
  618.     if(hp->xhp_PrivatePtr)
  619.     {
  620.       handleblock((struct TarBlockInfo *) hp->xhp_PrivatePtr); /* cleanup call */
  621.       xadFreeObjectA(hp->xhp_PrivatePtr, 0);
  622.       hp->xhp_PrivatePtr = 0;
  623.     }
  624.     /* break; */
  625.   case XADHC_ABORT: /* do nothing */
  626.     break;
  627.   default: err = XADERR_NOTSUPPORTED;
  628.   }
  629.  
  630.   if(!err && ((SetSignal(0L,0L) & SIGBREAKF_CTRL_C)))
  631.     err = XADERR_BREAK;
  632.  
  633.   return err;
  634. }
  635.  
  636. ASM(ULONG) progrhook(REG(a0, struct Hook *hook),
  637. REG(a1, struct xadProgressInfo *pi))
  638. {
  639.   ULONG ret = 0;
  640.   STRPTR name = ((struct xHookArgs *) (hook->h_Data))->name;
  641.  
  642.   switch(pi->xpi_Mode)
  643.   {
  644.   case XADPMODE_ASK:
  645.     ret |= ((struct xHookArgs *) (hook->h_Data))->flags;
  646.     if((pi->xpi_Status & XADPIF_OVERWRITE) && !(ret & XADPIF_OVERWRITE))
  647.     {
  648.       LONG r;
  649.  
  650.       Printf("\r\033[KFile '%s' already exists, overwrite? (Y|A|S|\033[1mN\033[0m|Q|R): ",
  651.       pi->xpi_FileName);
  652.       Flush(Output());
  653.       SetMode(Input(), TRUE);
  654.       r = FGetC(Input());
  655.       SetMode(Input(), FALSE);
  656.       switch(r)
  657.       {
  658.       case 'a': case 'A':
  659.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_OVERWRITE;
  660.       case 'y': case 'Y': ret |= XADPIF_OVERWRITE; break;
  661.       default:
  662.       /*case 's': case 'S': case 'n': case 'N':*/ ret |= XADPIF_SKIP; break;
  663.       case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); break;
  664.       case 'r': case 'R':
  665.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  666.         Flush(Output());
  667.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  668.         r = strlen(name);
  669.         if(name[r-1] == '\n') /* skip return character */
  670.           name[--r] = 0;
  671.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  672.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  673.         {
  674.           while(r--)
  675.             pi->xpi_NewName[r] = name[r];
  676.           ret |= XADPIF_RENAME;
  677.         }
  678.         else
  679.           Printf("No memory to store new name\n");
  680.       }
  681.     }
  682.     if((pi->xpi_Status & XADPIF_MAKEDIRECTORY) &&
  683.     !(ret & XADPIF_MAKEDIRECTORY))
  684.     {
  685.       Printf("\r\033[KDirectory of file '%s' does not exist, create? (Y|A|S|\033[1mN\033[0m|Q): ",
  686.       name);
  687.       Flush(Output());
  688.       SetMode(Input(), TRUE);
  689.       switch(FGetC(Input()))
  690.       {
  691.       case 'a': case 'A':
  692.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_MAKEDIRECTORY;
  693.       case 'y': case 'Y': ret |= XADPIF_MAKEDIRECTORY; break;
  694.       case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); break;
  695.       default:
  696.       /*case 's': case 'S': case 'n': case 'N':*/ ret |= XADPIF_SKIP; break;
  697.       }
  698.       SetMode(Input(), FALSE);
  699.     }
  700.     break;
  701.   case XADPMODE_PROGRESS:
  702.     if(pi->xpi_CurrentSize - ((struct xHookArgs *) (hook->h_Data))->lastprint >= MINPRINTSIZE)
  703.     {
  704.       Printf("\r\033[KWrote %8ld of %8ld bytes: %s",
  705.       pi->xpi_CurrentSize, ((struct xHookArgs *) (hook->h_Data))->size, name);
  706.       Flush(Output());
  707.       ((struct xHookArgs *) (hook->h_Data))->lastprint = pi->xpi_CurrentSize;
  708.     }
  709.     break;
  710.   case XADPMODE_END: Printf("\r\033[KWrote %8ld bytes: %s\n", pi->xpi_CurrentSize, name);
  711.     break;
  712.   case XADPMODE_ERROR: Printf("\r\033[K%s: %s\n", name, xadGetErrorText(pi->xpi_Error));
  713.     break;
  714.   }
  715.  
  716.   if(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)) /* clear ok flag */
  717.     ret |= XADPIF_OK;
  718.  
  719.   return ret;
  720. }
  721.  
  722. static void ShowProt(ULONG i)
  723. {
  724.   LONG j;
  725.   UBYTE buf[16], *b = "rwedrwedhsparwed";
  726.   
  727.   for(j = 0; j <= 11; ++j)
  728.     buf[j] = (i & (1<<(15-j))) ? b[j] : '-';
  729.   for(; j <= 15; ++j)
  730.     buf[j] = (i & (1<<(15-j))) ? '-' : b[j];
  731.  
  732.   Printf("%.16s ", buf);
  733. }
  734.  
  735. static LONG CheckNameSize(STRPTR name, ULONG size)
  736. {
  737.   LONG ret = 0;
  738.   LONG r;
  739.  
  740.   if((r = strlen(name)) > size)
  741.   {
  742.     UBYTE buf[NAMEBUFSIZE];
  743.  
  744.     Printf("\r\033[KFilename '%s' exceeds name limit of %ld by %ld, rename? (Y|\033[1mN\033[0m|Q): ", name, size, r-size);
  745.  
  746.     Flush(Output());
  747.     SetMode(Input(), TRUE);
  748.     r = FGetC(Input());
  749.     SetMode(Input(), FALSE);
  750.     switch(r)
  751.     {
  752.     case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); ret = 1; break;
  753.     case 'y': case 'Y':
  754.       Printf("\r\033[KEnter new name for '%s':", name);
  755.       Flush(Output());
  756.       FGets(Input(), buf, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  757.       r = strlen(buf);
  758.       if(buf[r-1] == '\n') /* skip return character */
  759.         buf[--r] = 0;
  760.       Printf("\033[1F\033[K"); /* go up one line and clear it */
  761.       if(!(ret = CheckNameSize(buf, size)))
  762.       {
  763.         for(r = 0; buf[r]; ++r)
  764.           *(name++) = buf[r];
  765.         *name = 0;
  766.       }
  767.       break;
  768.     }
  769.   }
  770.   return ret;
  771. }
  772.  
  773. /* would be better to store the pattern parse stuff and do it only once,
  774. but so it is a lot easier */
  775. static LONG CheckName(STRPTR *pat, STRPTR name)
  776. {
  777.   UBYTE buf[PATBUFSIZE];
  778.   while(*pat)
  779.   {
  780.     if(ParsePatternNoCase(*(pat++), buf, PATBUFSIZE) >= 0)
  781.     {
  782.       if(MatchPatternNoCase(buf, name))
  783.         return 1;
  784.     } /* A scan failure means no recognition, should be an error print here */
  785.   }
  786.   return 0;
  787. }
  788.