"Fossies" - the Fresh Open Source Software Archive

Member "afio-2.5.2/compfile.c" (30 Nov 2018, 9723 Bytes) of package /linux/misc/afio-2.5.2.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "compfile.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5.1_vs_2.5.2.

    1 /* afio file compresssion code */
    2 
    3 #include <stdio.h>
    4 #include <errno.h>
    5 #include <unistd.h>
    6 #include <string.h>
    7 
    8 #include <limits.h>
    9 #include <stdlib.h>
   10 #include <sys/signal.h>
   11 #include <sys/types.h>
   12 #include <sys/stat.h>
   13 
   14 #include "patchlevel.h"
   15 
   16 #include "afio.h"
   17 
   18 int matchcompext(char *);
   19 void meminit(void);
   20 void memwrite(char *buf, int count);
   21 int setupgzip(char *name);
   22 
   23 int zipfdfd;
   24 
   25 /* default value vor gzip 1.2.3 */
   26 int gzipfactor=6;
   27 
   28 /* compress all files? */
   29 int forceZflag = 0;
   30 
   31 /* this can be set to use something else but gzip: */
   32 char *compressprog = NULL;
   33 int compressargs = 0;
   34 
   35 
   36 /* max. (virtual) memory usage for -Z option */
   37 off_t maxmem=250*1024*1024;
   38 
   39 /* files whose length is below this length won't be compressed */
   40 long compthreshold=0;
   41 
   42 
   43 /* stuff to build argument list for compression/decompression : */
   44 
   45 #define MAX_ARGS  101
   46 
   47 char    * compress_arg_list[MAX_ARGS+1];
   48 /* MAX_ARGS+1 because we need to leave room for a NULL to mark the end */
   49 int compress_arg_no = 1;
   50 
   51 void    add_arg(char *arg)
   52 {
   53     if((compress_arg_no == 1)&&(*arg=='\0'))
   54     {
   55     /* special case: -Q "" means no arguments. */
   56     return;
   57     }
   58 
   59     if(compress_arg_no < MAX_ARGS )
   60     compress_arg_list[compress_arg_no++] = arg;
   61     else
   62     {
   63     fprintf (stderr, "afio: Fatal: maximium number of -Q arguments exceeded.\n");
   64     exit(1);
   65     }
   66 
   67 }
   68 
   69 /*
   70  * meminit, memwrite, memreset, memread, memfree.
   71  */
   72 
   73 int memerror;
   74 char *membank=NULL;
   75 size_t allocsize=0;
   76 size_t memsize,membytesread,membytesleft;
   77 
   78 void meminit(void)
   79 {
   80  memerror=0;
   81  memsize=0;
   82  /* RWWH: Initialize only the first time */
   83  if (!allocsize) {
   84    allocsize=100000;
   85    membank=(char *)malloc(allocsize);
   86    if(membank==NULL)
   87    {
   88        warn_nocount("Memory","Low on virtual memory, zipping twice instead.");
   89        memerror=1;
   90        allocsize=0;
   91    }
   92  }
   93 }
   94 
   95 void memwrite(char *buf, int count)
   96 {
   97  char *oldbank;
   98 
   99  if(memerror) return;
  100 
  101  oldbank=membank;
  102  /* RWWH: don't increase by linear amount! grow exponentially! */
  103  if (memsize+count>=allocsize) {
  104    allocsize=1.25*(memsize+count);
  105    if(allocsize/1024L/1024L > 2000)
  106      {
  107        /* safety: to avoid possible errors due to use of 32 bit int
  108           and size_t types here and there, prevent membank going over 2GB if
  109       compression programm actually expands filesize.
  110       Note that -M is capped at 1.5GB anyway.
  111        */
  112        membank=NULL; /* simulate realloc running out of memory */
  113      }
  114    else
  115      {
  116        membank=(char *)realloc(membank,allocsize);
  117      }
  118    if(membank==NULL)
  119     {
  120       warn_nocount("Memory","Low on virtual memory, zipping twice instead.");
  121       /* The free() both works and is necessary.  I can't recall what
  122          manpage documents this. */
  123       free(oldbank);
  124       memerror=1;
  125       allocsize=0;
  126       return;
  127     }
  128  }
  129 
  130  memcpy(membank+memsize,buf,(size_t)count);
  131  memsize+=count;
  132 }
  133 
  134 void memreset()
  135 {
  136  membytesread=0;
  137  membytesleft=memsize;
  138 }
  139 
  140 int memread(char *buf,int count)
  141 {
  142  if(membytesleft==0) return 0;
  143 
  144  if ((size_t)count > membytesleft) count=membytesleft;
  145  memcpy(buf,membank+membytesread,(size_t)count);
  146  membytesread+=count;
  147  membytesleft-=count;
  148  return count;
  149 }
  150 
  151 void memfree()
  152 {
  153  /* We do not free anymore, this should speed things up. */
  154 #if 0
  155  if(memerror==0) free(membank);
  156  allocsize=0;
  157 #endif
  158 }
  159 
  160 
  161 /*******/
  162 
  163 /*
  164  * Fork a gzip zipping the file name. The zipped version is output through a
  165  * pipe, the pipe handle is returned.
  166  * Returns -1 on failure.
  167  */
  168 int comppid;
  169 
  170 int setupgzip(char *name)
  171 {
  172  int pipedes[2];
  173  char farg[3];
  174 
  175  farg[0]='-';
  176  farg[1]=gzipfactor+'0';
  177  farg[2]='\0';
  178 
  179  if(pipe(pipedes)==-1) { perror("pipe"); return -1; }
  180 
  181  mayberewind();
  182 
  183  if ((comppid = xfork ("out(), compressing", NODIE)) == 0)
  184     {
  185       if (arfd != STDIN && arfd != STDOUT) VOID close (arfd);
  186 
  187       dup2(pipedes[1],fileno(stdout));
  188       close(pipedes[1]);
  189       close(pipedes[0]);
  190 
  191       VOID close (fileno (stdin));
  192 
  193       if (open (name, O_RDONLY) >= 0)
  194       {
  195       if(! compressargs)
  196           execlp (compressprog, compressprog, "-c", farg, NULL);
  197       else
  198           execvp (compressprog, compress_arg_list);
  199       }
  200       exit (1);
  201    }
  202 
  203  close(pipedes[1]);
  204 
  205  /* fprintf(stderr,"pid %d init, pipedes=%d.\n",comppid,pipedes[0]);  */
  206 
  207  return pipedes[0];
  208 }
  209 
  210 #include <sys/wait.h>
  211 #include <sys/types.h>
  212 
  213 void waitforgzip()
  214 {
  215  /* fprintf(stderr,"wait for gzip %d.\n",comppid); */
  216 
  217  xwait (comppid, "out(), wait for gzip child", FALSE);
  218 }
  219 
  220 /*
  221  * compress "name" if we can
  222  * If we compress we change the statbuf size, the file name, close
  223  * the old pointer to the file and return the pointer to the compressed
  224  * version;
  225  */
  226 
  227 #if ( defined(sun) && defined(__svr4__) ) || defined(__CYGWIN32__)
  228 #include <dirent.h>
  229 #else
  230 #include <sys/dir.h>
  231 #endif
  232 
  233 void
  234 compressfile (int *fdp, char *name, reg Stat *asb, int *cratio) {
  235   int compout;
  236   char *tmpcomp;
  237   Stat asb2;
  238   int zipfd;
  239   ssize_t len;
  240   char buf[40960];
  241   off_t ziplen;
  242   int usemem;
  243 
  244   if (cratio)
  245     *cratio = 100;
  246 
  247   /* We need to mark the file as being suitable or not for decompression on
  248      reading the archive. This is done by adding a .z extension.
  249 
  250      There is a problem with this: a file that is not suitable for
  251      compression may already have such an extension.
  252      Since this is a regular file, we can use the
  253      device number to indicate something weird going on here.
  254 
  255      We look at the bit (asb->sb_rdev)&RDEV_NOTCOMPR:
  256      If it is 1, it means that the file wasn't suitable for compression,
  257      and thus that any .z present was there on the original name.
  258      If it is 0, this does NOT imply that the file was compressed by afio.
  259 
  260      Note that it being 0 doesn't mean `decompress me', it merely
  261      indicates that a .z extender, _if_ _present_, was added by afio.
  262      (However, as of version 2.3.6, false does mean that the file was
  263      compressed by afio and a .z extender added.  In older archives one may
  264      see filenames with the bit 0 and not ending in .z. Such files
  265      have a compressed version larger than the original.)
  266 
  267      In pre-2.4.4 versions, files with size 0 do not have the bit
  268      set to 1.
  269   */
  270 
  271   /* indicate unsuitable for compression, may change it later */
  272    asb->sb_rdev |= RDEV_NOTCOMPR;
  273 
  274   /* Hard link handling code will break if we do compression on the
  275      file, so try to compress only if no links or hard link handling.
  276      Note that if forceZflag==1 than also lflag==1 was set, so this
  277      test will never return false.
  278 
  279      Also only try to compress if not already compressed,
  280      or length is >= threshold, or <= maxsizetocompress,
  281      but always try if we force compression
  282   */
  283 
  284   if ( (lflag || (asb->sb_nlink == 1))
  285        &&
  286        ( ( !matchcompext(name)
  287            && (asb->sb_size >= compthreshold)
  288            && ((maxsizetocompress==0) || ((ulonglong)(asb->sb_size) <= maxsizetocompress))
  289        )
  290      || forceZflag
  291        )
  292      )
  293   {
  294     /* make sure compress could put on the .Z */
  295     if ((tmpcomp = strrchr (name, '/')) != NULL)
  296       tmpcomp++;
  297     else
  298       tmpcomp = name;
  299 #ifdef NAME_MAX
  300     if (strlen (tmpcomp) + 2 > NAME_MAX)
  301 #else
  302 #ifdef MAXNAMLEN       /* BSD otherwise should be sysV (FFS on sysV?) */
  303     if (strlen (tmpcomp) + 2 > MAXNAMLEN)
  304 #else
  305     if (strlen (tmpcomp) + 2 > DIRSIZ)
  306 #endif /* MAXNAMLEN */
  307 #endif /* NAME_MAX */
  308       {
  309 #ifndef LONGZFILE
  310     VOID warn (name, " is too long to tack on .z");
  311     return;
  312 #endif
  313       }
  314 
  315   /*  fprintf(stderr,"---nam: %s, len: %d ziplen: ",name,asb->sb_size); */
  316 
  317     usemem=1;
  318 
  319     if((zipfd=setupgzip(name))!=-1)
  320       {
  321         ziplen=0;
  322         if(usemem) meminit();
  323         while((len=read(zipfd,buf,sizeof(buf)))!=0)
  324           {
  325            if(len<0) {  fprintf(stderr,
  326                           "Trouble zipping file, storing uncompressed\n");
  327                         /* read error on pipe, do not use gzip on this file */
  328                         ziplen=0; break;
  329                      }
  330            if(usemem) memwrite(buf,len);
  331 
  332            ziplen+=len;
  333            /* too much memory used? */
  334            if(usemem && ziplen>maxmem)
  335          { /* prepare to zip twice and free memory */
  336                usemem=0;
  337                if (!memerror) memfree();
  338                /* fprintf(stderr,"zipping twice."); */
  339          }
  340       }
  341         close(zipfd);
  342 
  343         /* wait for child to exit */
  344         if(xwait (comppid, "out(), wait for gzip child", FALSE)!= 0)
  345             {  fprintf(stderr,
  346                     "Trouble zipping file, storing uncompressed\n");
  347                ziplen=0;
  348             }
  349 
  350         if(memerror) usemem=0;
  351 
  352     /*   fprintf(stderr,"%ld\n",ziplen); */
  353         asb2.sb_size=ziplen;
  354 
  355     if (ziplen>0)
  356       {
  357         /* if compressed file is smaller than original, of if forceZflag
  358            is set, use compressed data */
  359         if (asb2.sb_size < asb->sb_size || forceZflag )
  360           {
  361                 if(usemem)
  362                   {
  363                     close (*fdp);
  364                     strcat (name, ".z");
  365                     /* was suitable for compression */
  366                     asb->sb_rdev &= ~RDEV_NOTCOMPR;
  367 
  368             if (cratio)
  369               *cratio = (int)((asb2.sb_size * 100.0) / asb->sb_size);
  370             asb->sb_size = asb2.sb_size;
  371             *fdp = MEMFD;
  372           }
  373                 else
  374           if ((compout = setupgzip(name)) >= 0)
  375                     {
  376                       zipfdfd=compout;
  377                       compout=ZIPFD;
  378 
  379                       close (*fdp);
  380                       strcat (name, ".z");
  381                       /* was suitable for compression */
  382               asb->sb_rdev &= ~RDEV_NOTCOMPR;
  383 
  384               if (cratio)
  385             *cratio = (int)((asb2.sb_size * 100.0) / asb->sb_size);
  386               asb->sb_size = asb2.sb_size;
  387               *fdp = compout;
  388             }
  389           }
  390             else
  391               {
  392                 if(usemem) memfree();
  393           }
  394       }
  395       }
  396 
  397   }
  398 }
  399 
  400