home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Magazine / wwwoffle-2.1.tar.gz / wwwoffle-2.1 / purge.c < prev    next >
C/C++ Source or Header  |  1998-02-21  |  8KB  |  289 lines

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/purge.c 2.7 1997/12/27 16:58:20 amb Exp $
  3.  
  4.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.0a.
  5.   Purge old files from the cache.
  6.   ******************/ /******************
  7.   Written by Andrew M. Bishop
  8.  
  9.   This file Copyright 1996,97 Andrew M. Bishop
  10.   It may be distributed under the GNU Public License, version 2, or
  11.   any higher version.  See section COPYING of the GNU Public license
  12.   for conditions under which this file may be redistributed.
  13.   ***************************************/
  14.  
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19.  
  20. #include <time.h>
  21. #include <utime.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <time.h>
  25. #include <dirent.h>
  26. #include <unistd.h>
  27.  
  28. #include "wwwoffle.h"
  29. #include "misc.h"
  30. #include "proto.h"
  31. #include "config.h"
  32. #include "errors.h"
  33.  
  34.  
  35. /* Local functions */
  36. static int PurgeFiles(char *proto,char *host,time_t now,int age,int *bytes_age);
  37.  
  38. /*+ Set this to 0 for debugging so that nothing is deleted. +*/
  39. #define DO_DELETE 1
  40.  
  41.  
  42. /*++++++++++++++++++++++++++++++++++++++
  43.   Purge files from the cache that meet the age criteria.
  44.  
  45.   int fd the file descriptor of the wwwoffle client.
  46.   ++++++++++++++++++++++++++++++++++++++*/
  47.  
  48. void PurgeCache(int fd)
  49. {
  50.  time_t now=time(NULL)+60;
  51.  int total_bytes=0,total_dirs=0;
  52.  int i,p,pass;
  53.  int age_for_size=-1;
  54.  int *nbytes_by_age=(int*)malloc((DefaultPurgeAge+1)*sizeof(int));
  55.  
  56.  for(i=0;i<=DefaultPurgeAge;i++)
  57.     nbytes_by_age[i]=0;
  58.  
  59.  if(PurgeUseMTime)
  60.     write_string(fd,"(Using modification time.)\n");
  61.  else
  62.     write_string(fd,"(Using last access time.)\n");
  63.  
  64.  for(pass=1;pass<=2;pass++)
  65.    {
  66.     if(PurgeCacheSize)
  67.        if(pass==1)
  68.           write_string(fd,"\nPass 1: Checking dates and sizes of files.\n");
  69.        else
  70.           write_string(fd,"\nPass 2: Purging files down to specified size.\n");
  71.  
  72.     write_string(fd,"\n");
  73.  
  74.     for(p=0;p<NProtocols;p++)
  75.       {
  76.        DIR *dir;
  77.        struct dirent* ent;
  78.        struct stat buf;
  79.        char *proto=Protocols[p].name;
  80.  
  81.        /* Open the spool directory. */
  82.  
  83.        if(stat(proto,&buf))
  84.          {PrintMessage(Inform,"Cannot stat directory '%s' [%!s]; not purged",proto);continue;}
  85.  
  86.        if(chdir(proto))
  87.          {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; not purged.",proto);continue;}
  88.  
  89.        dir=opendir(".");
  90.        if(!dir)
  91.          {PrintMessage(Warning,"Cannot open directory '%s' [%!s]; not purged.",proto);chdir("..");continue;}
  92.  
  93.        ent=readdir(dir);  /* skip .  */
  94.        if(!ent)
  95.          {PrintMessage(Warning,"Cannot read directory '%s' [%!s]; not purged.",proto);closedir(dir);chdir("..");continue;}
  96.        ent=readdir(dir);  /* skip .. */
  97.  
  98.        /* Search through all of the sub directories. */
  99.  
  100.        while((ent=readdir(dir)))
  101.          {
  102.           struct stat buf;
  103.  
  104.           if(lstat(ent->d_name,&buf))
  105.              PrintMessage(Inform,"Cannot stat file '%s/%s' [%!s]; race condition?",proto,ent->d_name);
  106.           else if(S_ISDIR(buf.st_mode))
  107.             {
  108.              int bytes=0;
  109.              int age=WhatPurgeAge(proto,ent->d_name);
  110.  
  111.              if(age<0)
  112.                 bytes=PurgeFiles(proto,ent->d_name,now,-1,nbytes_by_age);
  113.              else
  114.                {
  115.                 if(pass==2)
  116.                    age=age_for_size;
  117.                 bytes=PurgeFiles(proto,ent->d_name,now,age,nbytes_by_age);
  118.  
  119.                 if(bytes==-1)
  120.                   {
  121. #if DO_DELETE
  122.                    if(rmdir(ent->d_name))
  123.                       PrintMessage(Warning,"Cannot delete what should be an empty directory '%s/%s' [%!s].",proto,ent->d_name);
  124. #else
  125.                    PrintMessage(Debug,"rmdir(%s/%s).",proto,ent->d_name);
  126. #endif
  127.                   }
  128.                 else
  129.                   {
  130.                    struct utimbuf utbuf;
  131.  
  132.                    utbuf.actime=buf.st_atime;
  133.                    utbuf.modtime=buf.st_mtime;
  134.                    utime(ent->d_name,&utbuf);
  135.                   }
  136.                }
  137.  
  138.              if(bytes>0)
  139.                 total_bytes+=bytes;
  140.              if(bytes>=0)
  141.                 total_dirs++;
  142.  
  143.              if(age<0)
  144.                 write_formatted(fd,"Not Purged       %8s://%-32s ; %5d kB.\n",proto,ent->d_name,(bytes+512)/1024);
  145.              else if(bytes==-1)
  146.                 write_formatted(fd,"Purged (%2d days) %8s://%-32s ; (empty) - deleted.\n",age,proto,ent->d_name);
  147.              else
  148.                 write_formatted(fd,"Purged (%2d days) %8s://%-32s ; %5d kB.\n",age,proto,ent->d_name,(bytes+512)/1024);
  149.             }
  150.          }
  151.  
  152.        closedir(dir);
  153.        chdir("..");
  154.       }
  155.  
  156.     write_formatted(fd,"Total of %d directories ; %d kB.\n",total_dirs,(total_bytes+512)/1024);
  157.  
  158.     if(pass==1)
  159.       {
  160.        write_string(fd,"\n");
  161.  
  162.        for(total_bytes=i=0;i<=DefaultPurgeAge;i++)
  163.          {
  164.           total_bytes+=nbytes_by_age[i];
  165.  
  166.           if(PurgeCacheSize && age_for_size<0 && ((total_bytes+512)/1024)>(1024*PurgeCacheSize))
  167.             {
  168.              age_for_size=i;
  169.              write_formatted(fd,"Cutoff Age is %2d days for %3d MB.\n",age_for_size,PurgeCacheSize);
  170.             }
  171.  
  172.           if(i==DefaultPurgeAge)
  173.              write_formatted(fd,"Total all ages     ; %5d kB.\n",(total_bytes+512)/1024);
  174.           else
  175.              write_formatted(fd,"Newer than %2d day%c ; %5d kB.\n",i+1,i?'s':' ',(total_bytes+512)/1024);
  176.          }
  177.        total_bytes=0;
  178.       }
  179.  
  180.     if(!PurgeCacheSize || age_for_size==-1)
  181.        break;
  182.    }
  183.  
  184.  write_string(fd,"\n");
  185.  
  186.  free(nbytes_by_age);
  187. }
  188.  
  189.  
  190. /*++++++++++++++++++++++++++++++++++++++
  191.   Delete the file in the current directory that are older than the specified age.
  192.  
  193.   int PurgeFiles Returns the number of bytes in files that are left.
  194.  
  195.   char *proto The name of the protocol directory to purge.
  196.  
  197.   char *host The name of the host directory to purge.
  198.  
  199.   time_t now The current time (in seconds).
  200.  
  201.   int age The age that is specified for the directory in days.
  202.  
  203.   int *bytes_age An array that contains the number of bytes for a given age.
  204.   ++++++++++++++++++++++++++++++++++++++*/
  205.  
  206. static int PurgeFiles(char *proto,char *host,time_t now,int age,int *bytes_age)
  207. {
  208.  int bytes_left=-1;
  209.  long oldest=0;
  210.  DIR *dir;
  211.  struct dirent* ent;
  212.  
  213.  if(age>=0)
  214.     oldest=now-age*(24*3600);
  215.  
  216.  /* Open the spool subdirectory. */
  217.  
  218.  if(chdir(host))
  219.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s]; not purged.",proto,host);return(1);}
  220.  
  221.  dir=opendir(".");
  222.  if(!dir)
  223.    {PrintMessage(Warning,"Cannot open directory '%s/%s' [%!s]; not purged.",proto,host);chdir("..");return(1);}
  224.  
  225.  ent=readdir(dir);  /* skip .  */
  226.  if(!ent)
  227.    {PrintMessage(Warning,"Cannot read directory '%s/%s' [%!s]; not purged.",proto,host);closedir(dir);chdir("..");return(1);}
  228.  ent=readdir(dir);  /* skip .. */
  229.  
  230.  /* Check all of the files for age, and delete as needed. */
  231.  
  232.  while((ent=readdir(dir)))
  233.    {
  234.     struct stat buf;
  235.  
  236.     if(stat(ent->d_name,&buf))
  237.        PrintMessage(Inform,"Cannot stat file '%s/%s/%s' [%!s]; race condition?",proto,host,ent->d_name);
  238.     else
  239.       {
  240.        time_t t;
  241.  
  242.        if(PurgeUseMTime)
  243.           t=buf.st_mtime;
  244.        else
  245.           t=buf.st_atime;
  246.  
  247.        if(t>oldest)
  248.          {
  249.           if(bytes_left==-1)
  250.              bytes_left=0;
  251.           bytes_left+=buf.st_size;
  252.           if(age>0)
  253.             {
  254.              int days=(now-t)/(24*3600);
  255.              if(days>DefaultPurgeAge)
  256.                 days=DefaultPurgeAge;
  257.              bytes_age[days]+=buf.st_size;
  258.             }
  259.          }
  260.        else
  261.          {
  262. #if DO_DELETE
  263.           if(unlink(ent->d_name))
  264.              PrintMessage(Warning,"Cannot unlink file '%s/%s/%s' [%!s].",proto,host,ent->d_name);
  265. #else
  266.           PrintMessage(Debug,"unlink(%s/%s/%s).",proto,host,ent->d_name);
  267. #endif
  268.  
  269.           if(*ent->d_name=='D')
  270.             {
  271.              *ent->d_name='U';
  272.  
  273. #if DO_DELETE
  274.              if(unlink(ent->d_name))
  275.                 PrintMessage(Warning,"Cannot unlink file '%s/%s/%s' [%!s].",proto,host,ent->d_name);
  276. #else
  277.              PrintMessage(Debug,"unlink(%s/%s/%s).",proto,host,ent->d_name);
  278. #endif
  279.             }
  280.          }
  281.       }
  282.    }
  283.  
  284.  closedir(dir);
  285.  chdir("..");
  286.  
  287.  return(bytes_left);
  288. }
  289.