spool.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:33k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/spool.c 2.50 1999/11/27 16:02:28 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5c.
  4.   Handle all of the spooling of files in the spool directory.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1996,97,98,99 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #include <utime.h>
  17. #include <sys/stat.h>
  18. #include <dirent.h>
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <errno.h>
  22. #include <ctype.h>
  23. #include "wwwoffle.h"
  24. #include "misc.h"
  25. #include "errors.h"
  26. #include "config.h"
  27. /*+ Need this for Win32 to use binary mode +*/
  28. #ifndef O_BINARY
  29. #define O_BINARY 0
  30. #endif
  31. /*++++++++++++++++++++++++++++++++++++++
  32.   Open a file in the outgoing directory to write into / read from.
  33.   int OpenOutgoingSpoolFile Returns a file descriptor, or -1 on failure.
  34.   int rw Set to true to read, else false.
  35.   ++++++++++++++++++++++++++++++++++++++*/
  36. int OpenOutgoingSpoolFile(int rw)
  37. {
  38.  struct stat buf;
  39.  int fd=-1;
  40.  char name[16];
  41.  sprintf(name,"tmp.%ld",(long)getpid());
  42.  /* Create the outgoing directory if needed and change to it */
  43.  if(lstat("outgoing",&buf))
  44.    {
  45.     PrintMessage(Inform,"Directory 'outgoing' does not exist [%!s]; creating one.");
  46.     if(mkdir("outgoing",DirPerm))
  47.       {PrintMessage(Warning,"Cannot create directory 'outgoing' [%!s].");return(-1);}
  48.    }
  49.  else
  50.     if(!S_ISDIR(buf.st_mode))
  51.       {PrintMessage(Warning,"The file 'outgoing' is not a directory.");return(-1);}
  52.  if(chdir("outgoing"))
  53.    {PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s].");return(-1);}
  54.  /* Open the outgoing file */
  55.  if(rw)
  56.    {
  57.     struct dirent* ent;
  58.     DIR *dir=opendir(".");
  59.     if(!dir)
  60.       {PrintMessage(Warning,"Cannot open current directory 'outgoing' [%!s].");chdir("..");return(-1);}
  61.     ent=readdir(dir);  /* skip .  */
  62.     if(!ent)
  63.       {PrintMessage(Warning,"Cannot read current directory 'outgoing' [%!s].");closedir(dir);chdir("..");return(-1);}
  64.     ent=readdir(dir);  /* skip .. */
  65.     while((ent=readdir(dir)))
  66.        if(*ent->d_name=='O')
  67.          {
  68.           if(rename(ent->d_name,name))
  69.              PrintMessage(Inform,"Cannot rename file 'outgoing/%s' to 'outgoing/%s' [%!s]; race condition?",ent->d_name,name);
  70.           else
  71.             {
  72.              fd=open(name,O_RDONLY|O_BINARY);
  73.              if(fd==-1)
  74.                 PrintMessage(Inform,"Cannot open file 'outgoing/%s' [%!s]; race condition?",name);
  75.              else
  76.                {
  77.                 *ent->d_name='U';
  78.                 unlink(ent->d_name);
  79.                 unlink(name);
  80.                 break;
  81.                }
  82.             }
  83.          }
  84.     closedir(dir);
  85.    }
  86.  else
  87.    {
  88.     fd=open(name,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,FilePerm);
  89.     if(fd==-1)
  90.        PrintMessage(Warning,"Cannot open file 'outgoing/%s' [%!s]",name);
  91.    }
  92.  /* Change dir back and tidy up. */
  93.  chdir("..");
  94.  return(fd);
  95. }
  96. /*++++++++++++++++++++++++++++++++++++++
  97.   Close an outgoing spool file and rename it to the hashed name.
  98.   int fd The file descriptor to close.
  99.   URL *Url The URL to close.
  100.   ++++++++++++++++++++++++++++++++++++++*/
  101. void CloseOutgoingSpoolFile(int fd,URL *Url)
  102. {
  103.  char oldname[16],*newname;
  104.  int ufd;
  105.  close(fd);
  106.  /* Change to the outgoing directory. */
  107.  if(chdir("outgoing"))
  108.    {PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s].");return;}
  109.  /* Create and rename the file */
  110.  sprintf(oldname,"tmp.%ld",(long)getpid());
  111.  newname=URLToFileName(Url);
  112.  *newname='U';
  113.  unlink(newname);
  114.  ufd=open(newname,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,FilePerm);
  115.  if(ufd!=-1)
  116.    {
  117.     write_string(ufd,Url->file);
  118.     close(ufd);
  119.    }
  120.  *newname='O';
  121.  if(rename(oldname,newname))
  122.    {PrintMessage(Warning,"Cannot rename 'outgoing/%s' to 'outgoing/%s' [%!s].",oldname,newname);unlink(oldname);}
  123.  /* Change dir back and tidy up. */
  124.  chdir("..");
  125.  free(newname);
  126. }
  127. /*++++++++++++++++++++++++++++++++++++++
  128.   Check if a specified URL exists in the outgoing directory.
  129.   int ExistsOutgoingSpoolFile Returns a boolean.
  130.   URL *Url The URL to check for.
  131.   ++++++++++++++++++++++++++++++++++++++*/
  132. int ExistsOutgoingSpoolFile(URL *Url)
  133. {
  134.  struct stat buf;
  135.  char *name;
  136.  int exists=0;
  137.  if(chdir("outgoing"))
  138.    {PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s].");return(0);}
  139.  /* Stat the outgoing file */
  140.  name=URLToFileName(Url);
  141.  *name='O';
  142.  exists=!stat(name,&buf);
  143.  /* Change dir back and tidy up. */
  144.  chdir("..");
  145.  free(name);
  146.  return(exists);
  147. }
  148. /*++++++++++++++++++++++++++++++++++++++
  149.   Create a hash value from the request for a specified URL in the outgoing directory.
  150.   int HashOutgoingSpoolFile Returns a hash string or NULL in error.
  151.   URL *Url The URL to create the hash for.
  152.   ++++++++++++++++++++++++++++++++++++++*/
  153. char *HashOutgoingSpoolFile(URL *Url)
  154. {
  155.  char *name,*req,*hash;
  156.  int fd,r;
  157.  if(chdir("outgoing"))
  158.    {PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s].");return(NULL);}
  159.  /* Read the outgoing file */
  160.  name=URLToFileName(Url);
  161.  *name='O';
  162.  fd=open(name,O_RDONLY|O_BINARY);
  163.  if(fd==-1)
  164.    {PrintMessage(Warning,"Cannot open outgoing request to create hash [%!s].");free(name);chdir("..");return(NULL);}
  165.  req=(char*)malloc(256+1);
  166.  r=read(fd,req,256);
  167.  if(r==256)
  168.    {
  169.     int rr=0;
  170.     do
  171.       {
  172.        r+=rr;
  173.        req=(char*)realloc(req,r+256+1);
  174.       }
  175.     while((rr=read(fd,&req[r],256))>0);
  176.    }
  177.  else if(r==-1)
  178.    {PrintMessage(Warning,"Cannot read from outgoing request to create hash [%!s].");close(fd);free(name);free(req);chdir("..");return(NULL);}
  179.  req[r]=0;
  180.  close(fd);
  181.  hash=MakeHash(req);
  182.  /* Change dir back and tidy up. */
  183.  chdir("..");
  184.  free(name);
  185.  free(req);
  186.  return(hash);
  187. }
  188. /*++++++++++++++++++++++++++++++++++++++
  189.   Delete a specified URL request from the outgoing requests.
  190.   char *DeleteOutgoingSpoolFile Returns NULL if OK else error message.
  191.   URL *Url The URL to delete or NULL for all of them.
  192.   ++++++++++++++++++++++++++++++++++++++*/
  193. char *DeleteOutgoingSpoolFile(URL *Url)
  194. {
  195.  char *err=NULL;
  196.  /* Change to the outgoing directory. */
  197.  if(chdir("outgoing"))
  198.    {err=PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s].");return(err);}
  199.  /* Delete the file for the request or all of them. */
  200.  if(Url)
  201.    {
  202.     char *name;
  203.     name=URLToFileName(Url);
  204.     *name='O';
  205.     if(unlink(name))
  206.        err=PrintMessage(Warning,"Cannot unlink outgoing request 'outgoing/%s' [%!s].",name);
  207.     *name='U';
  208.     unlink(name);
  209.     free(name);
  210.    }
  211.  else
  212.    {
  213.     struct dirent* ent;
  214.     DIR *dir=opendir(".");
  215.     if(!dir)
  216.       {err=PrintMessage(Warning,"Cannot open current directory 'outgoing' [%!s].");chdir("..");return(err);}
  217.     ent=readdir(dir);  /* skip .  */
  218.     if(!ent)
  219.       {err=PrintMessage(Warning,"Cannot read current directory 'outgoing' [%!s].");closedir(dir);chdir("..");return(err);}
  220.     ent=readdir(dir);  /* skip .. */
  221.     while((ent=readdir(dir)))
  222.       {
  223.        if(unlink(ent->d_name))
  224.           err=PrintMessage(Warning,"Cannot unlink outgoing request 'outgoing/%s' [%!s].",ent->d_name);
  225.       }
  226.     closedir(dir);
  227.    }
  228.  /* Change dir back and tidy up. */
  229.  chdir("..");
  230.  return(err);
  231. }
  232. /*++++++++++++++++++++++++++++++++++++++
  233.   Open a file in a spool subdirectory to write into / read from.
  234.   int OpenWebpageSpoolFile Returns a file descriptor.
  235.   int rw Set to 1 to read, 0 to write.
  236.   URL *Url The URL to open.
  237.   ++++++++++++++++++++++++++++++++++++++*/
  238. int OpenWebpageSpoolFile(int rw,URL *Url)
  239. {
  240.  struct stat buf;
  241.  char *file;
  242.  int fd=-1;
  243.  /* Create the spool directory if needed and change to it. */
  244.  if(lstat(Url->proto,&buf))
  245.    {
  246.     PrintMessage(Inform,"Directory '%s' does not exist [%!s]; creating one.",Url->proto);
  247.     if(mkdir(Url->proto,DirPerm))
  248.       {PrintMessage(Warning,"Cannot create directory '%s' [%!s].",Url->proto);return(-1);}
  249.    }
  250.  else
  251.     if(!S_ISDIR(buf.st_mode))
  252.       {PrintMessage(Warning,"The file '%s' is not a directory.",Url->proto);return(-1);}
  253.  if(chdir(Url->proto))
  254.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return(-1);}
  255.  if(lstat(Url->dir,&buf))
  256.    {
  257.     PrintMessage(Inform,"Directory '%s/%s' does not exist [%!s]; creating one.",Url->proto,Url->dir);
  258.     if(mkdir(Url->dir,DirPerm))
  259.       {PrintMessage(Warning,"Cannot create directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return(-1);}
  260.    }
  261.  else
  262.     if(!S_ISDIR(buf.st_mode))
  263.       {PrintMessage(Warning,"The file '%s/%s' is not a directory.",Url->proto,Url->dir);chdir("..");return(-1);}
  264.  if(chdir(Url->dir))
  265.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return(-1);}
  266.  /* Open the file for the web page. */
  267.  file=URLToFileName(Url);
  268.  *file='D';
  269.  if(rw)
  270.     fd=open(file,O_RDONLY|O_BINARY);
  271.  else
  272.     fd=open(file,O_RDWR|O_CREAT|O_BINARY,FilePerm);
  273.  if(!rw && fd!=-1)
  274.    {
  275.     int ufd;
  276.     *file='U';
  277.     ufd=open(file,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,FilePerm);
  278.     if(ufd!=-1)
  279.       {
  280.        write_string(ufd,Url->file);
  281.        close(ufd);
  282.       }
  283.     else
  284.       {
  285.        close(fd);
  286.        fd=-1;
  287.       }
  288.    }
  289.  /* Change the modification time on the directory. */
  290.  if(!rw && fd!=-1)
  291.     utime(".",NULL);
  292.  chdir("..");
  293.  if(!rw && fd!=-1)
  294.     utime(".",NULL);
  295.  /* Change dir back and tidy up. */
  296.  chdir("..");
  297.  free(file);
  298.  return(fd);
  299. }
  300. /*++++++++++++++++++++++++++++++++++++++
  301.   Delete a file in a spool subdirectory.
  302.   char *DeleteWebpageSpoolFile Return NULL if OK else error message.
  303.   URL *Url The URL to delete.
  304.   int all If set then delete all pages from this host.
  305.   ++++++++++++++++++++++++++++++++++++++*/
  306. char *DeleteWebpageSpoolFile(URL *Url,int all)
  307. {
  308.  char *err=NULL;
  309.  /* Change to the spool directory. */
  310.  if(chdir(Url->proto))
  311.    {err=PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return(err);}
  312.  if(chdir(Url->dir))
  313.    {err=PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return(err);}
  314.  /* Delete the file for the web page. */
  315.  if(all)
  316.    {
  317.     struct dirent* ent;
  318.     DIR *dir=opendir(".");
  319.     if(!dir)
  320.       {err=PrintMessage(Warning,"Cannot open current directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("../..");return(err);}
  321.     ent=readdir(dir);  /* skip .  */
  322.     if(!ent)
  323.       {err=PrintMessage(Warning,"Cannot read current directory '%s/%s' [%!s].",Url->proto,Url->dir);closedir(dir);chdir("../..");return(err);}
  324.     ent=readdir(dir);  /* skip .. */
  325.     while((ent=readdir(dir)))
  326.       {
  327.        if(*ent->d_name=='D')
  328.          {
  329.           char *delurl;
  330.           if((delurl=FileNameToURL(ent->d_name)))
  331.             {
  332.              URL *delUrl=SplitURL(delurl);
  333.              chdir("../..");
  334.              if(ExistsLastTimeSpoolFile(delUrl))
  335.                 DeleteLastTimeSpoolFile(delUrl);
  336.              chdir(Url->proto);
  337.              chdir(Url->dir);
  338.              free(delurl);
  339.              FreeURL(delUrl);
  340.             }
  341.          }
  342.        if(unlink(ent->d_name))
  343.           err=PrintMessage(Warning,"Cannot unlink cached file '%s/%s/%s' [%!s].",Url->proto,Url->dir,ent->d_name);
  344.       }
  345.     closedir(dir);
  346.     chdir("..");
  347.     if(rmdir(Url->dir))
  348.       err=PrintMessage(Warning,"Cannot delete what should be an empty directory '%s/%s' [%!s].",Url->proto,Url->dir);
  349.     chdir("..");
  350.    }
  351.  else
  352.    {
  353.     char *file=URLToFileName(Url);
  354.     struct stat buf;
  355.     int didstat=1;
  356.     if(stat(".",&buf))
  357.        PrintMessage(Warning,"Cannot stat directory '%s/%s' [%!s].",Url->proto,Url->dir);
  358.     else
  359.        didstat=1;
  360.     *file='D';
  361.     if(unlink(file))
  362.        err=PrintMessage(Warning,"Cannot unlink cached file '%s/%s/%s' [%!s].",Url->proto,Url->dir,file);
  363.     *file='U';
  364.     unlink(file);
  365.     free(file);
  366.     if(didstat)
  367.       {
  368.        struct utimbuf utbuf;
  369.        utbuf.actime=time(NULL);
  370.        utbuf.modtime=buf.st_mtime;
  371.        utime(".",&utbuf);
  372.       }
  373.     chdir("../..");
  374.     if(ExistsLastTimeSpoolFile(Url))
  375.        DeleteLastTimeSpoolFile(Url);
  376.    }
  377.  return(err);
  378. }
  379. /*++++++++++++++++++++++++++++++++++++++
  380.   Touch a file in a spool subdirectory.
  381.   URL *Url The URL to touch.
  382.   time_t when The time to set the access time to.
  383.   ++++++++++++++++++++++++++++++++++++++*/
  384. void TouchWebpageSpoolFile(URL *Url,time_t when)
  385. {
  386.  char *file;
  387.  /* Change to the spool directory. */
  388.  if(chdir(Url->proto))
  389.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  390.  if(chdir(Url->dir))
  391.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  392.  /* Touch the file for the web page. */
  393.  file=URLToFileName(Url);
  394.  *file='D';
  395.  if(when)
  396.    {
  397.     struct stat buf;
  398.     if(stat(file,&buf))
  399.        utime(file,NULL);
  400.     else
  401.       {
  402.        struct utimbuf ubuf;
  403.        ubuf.actime=when;
  404.        ubuf.modtime=buf.st_mtime;
  405.        utime(file,&ubuf);
  406.       }
  407.    }
  408.  else
  409.     utime(file,NULL);
  410.  /* Change dir back and tidy up. */
  411.  chdir("../..");
  412.  free(file);
  413. }
  414. /*++++++++++++++++++++++++++++++++++++++
  415.   Check if a file in a spool subdirectory exists.
  416.   time_t ExistsWebpageSpoolFile Return a the time the page was last accessed if the page exists.
  417.   URL *Url The URL to check for.
  418.   ++++++++++++++++++++++++++++++++++++++*/
  419. time_t ExistsWebpageSpoolFile(URL *Url)
  420. {
  421.  struct stat buf;
  422.  char *file;
  423.  /* Change to the spool directory. */
  424.  if(chdir(Url->proto))
  425.     return(0);
  426.  if(chdir(Url->dir))
  427.    {chdir("..");return(0);}
  428.  /* Stat the file for the web page. */
  429.  file=URLToFileName(Url);
  430.  *file='D';
  431.  if(stat(file,&buf))
  432.     buf.st_atime=0;
  433.  /* Change dir back and tidy up. */
  434.  chdir("../..");
  435.  free(file);
  436.  return(buf.st_atime);
  437. }
  438. /*++++++++++++++++++++++++++++++++++++++
  439.   Create a backup copy of a file in a spool subdirectory.
  440.   URL *Url The URL to make a copy of.
  441.   ++++++++++++++++++++++++++++++++++++++*/
  442. void CreateBackupWebpageSpoolFile(URL *Url)
  443. {
  444.  struct stat buf;
  445.  char *bakfile,*orgfile;
  446.  /* Change to the spool directory. */
  447.  if(chdir(Url->proto))
  448.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  449.  if(chdir(Url->dir))
  450.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  451.  /* Create the filenames and rename the files. */
  452.  orgfile=URLToFileName(Url);
  453.  bakfile=(char*)malloc(strlen(orgfile)+2);
  454.  strcpy(bakfile,orgfile);
  455.  *bakfile=*orgfile='D';
  456.  strcat(bakfile,"~");
  457.  if(!stat(bakfile,&buf))
  458.     PrintMessage(Inform,"Backup already exists for '%s'.",Url->name);
  459.  else
  460.    {
  461.     if(rename(orgfile,bakfile))
  462.        PrintMessage(Warning,"Cannot rename backup cached file '%s/%s/%s' to %s [%!s].",Url->proto,Url->dir,bakfile,orgfile);
  463.     *bakfile=*orgfile='U';
  464.     rename(orgfile,bakfile);
  465.    }
  466.  /* Change dir back and tidy up. */
  467.  chdir("../..");
  468.  free(bakfile);
  469.  free(orgfile);
  470. }
  471. /*++++++++++++++++++++++++++++++++++++++
  472.   Restore the backup copy of a file in a spool subdirectory.
  473.   URL *Url The URL to restore.
  474.   ++++++++++++++++++++++++++++++++++++++*/
  475. void RestoreBackupWebpageSpoolFile(URL *Url)
  476. {
  477.  struct stat buf;
  478.  char *bakfile,*orgfile;
  479.  /* Change to the spool directory. */
  480.  if(chdir(Url->proto))
  481.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  482.  if(chdir(Url->dir))
  483.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  484.  /* Create the filenames and rename the files. */
  485.  orgfile=URLToFileName(Url);
  486.  bakfile=(char*)malloc(strlen(orgfile)+2);
  487.  strcpy(bakfile,orgfile);
  488.  *bakfile=*orgfile='D';
  489.  strcat(bakfile,"~");
  490.  if(!stat(bakfile,&buf))
  491.    {
  492.     if(rename(bakfile,orgfile))
  493.        PrintMessage(Warning,"Cannot rename backup cached file '%s/%s/%s' to %s [%!s].",Url->proto,Url->dir,bakfile,orgfile);
  494.     *bakfile=*orgfile='U';
  495.     rename(bakfile,orgfile);
  496.    }
  497.  /* Change dir back and tidy up. */
  498.  chdir("../..");
  499.  free(bakfile);
  500.  free(orgfile);
  501. }
  502. /*++++++++++++++++++++++++++++++++++++++
  503.   Delete a file in a spool subdirectory.
  504.   URL *Url The URL to delete.
  505.   ++++++++++++++++++++++++++++++++++++++*/
  506. void DeleteBackupWebpageSpoolFile(URL *Url)
  507. {
  508.  char *bakfile;
  509.  /* Change to the spool directory. */
  510.  if(chdir(Url->proto))
  511.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  512.  if(chdir(Url->dir))
  513.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  514.  /* Delete the file for the backup web page. */
  515.  bakfile=URLToFileName(Url);
  516.  *bakfile='D';
  517.  strcat(bakfile,"~");
  518.  if(unlink(bakfile))
  519.     PrintMessage(Warning,"Cannot unlink backup cached file '%s/%s/%s' [%!s].",Url->proto,Url->dir,bakfile);
  520.  *bakfile='U';
  521.  unlink(bakfile);
  522.  /* Change dir back and tidy up. */
  523.  chdir("../..");
  524.  free(bakfile);
  525. }
  526. /*++++++++++++++++++++++++++++++++++++++
  527.   Create a lock file in a spool subdirectory.
  528.   URL *Url The URL to lock.
  529.   ++++++++++++++++++++++++++++++++++++++*/
  530. void CreateLockWebpageSpoolFile(URL *Url)
  531. {
  532.  struct stat buf;
  533.  char *lokfile,*orgfile;
  534.  /* Change to the spool directory. */
  535.  if(chdir(Url->proto))
  536.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  537.  if(chdir(Url->dir))
  538.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  539.  /* Create the lock file for the web page. */
  540.  orgfile=URLToFileName(Url);
  541.  lokfile=(char*)malloc(strlen(orgfile)+2);
  542.  strcpy(lokfile,orgfile);
  543.  *lokfile='L';
  544.  *orgfile='D';
  545.  if(!stat(lokfile,&buf))
  546.     PrintMessage(Inform,"Lock file already exists for '%s'.",Url->name);
  547.  else
  548.    {
  549.     if(link(orgfile,lokfile))
  550.        PrintMessage(Warning,"Cannot make a lock file for '%s/%s/%s' [%!s].",Url->proto,Url->dir,orgfile);
  551.    }
  552.  /* Change dir back and tidy up. */
  553.  chdir("../..");
  554.  free(lokfile);
  555.  free(orgfile);
  556. }
  557. /*++++++++++++++++++++++++++++++++++++++
  558.   Check for the existance of a lock file in a spool subdirectory.
  559.   int ExistsLockWebpageSpoolFile Return a true value if the lock file exists.
  560.   URL *Url The URL to check for the lock file for.
  561.   ++++++++++++++++++++++++++++++++++++++*/
  562. int ExistsLockWebpageSpoolFile(URL *Url)
  563. {
  564.  struct stat buf;
  565.  char *file;
  566.  int exists=0;
  567.  if(chdir(Url->proto))
  568.     return(0);
  569.  if(chdir(Url->dir))
  570.    {chdir("..");return(0);}
  571.  /* Stat the file for the web page. */
  572.  file=URLToFileName(Url);
  573.  *file='L';
  574.  exists=!stat(file,&buf);
  575.  /* Change dir back and tidy up. */
  576.  chdir("../..");
  577.  free(file);
  578.  return(exists);
  579. }
  580. /*++++++++++++++++++++++++++++++++++++++
  581.   Delete a lock file in a spool subdirectory.
  582.   URL *Url The URL with the lock to delete.
  583.   ++++++++++++++++++++++++++++++++++++++*/
  584. void DeleteLockWebpageSpoolFile(URL *Url)
  585. {
  586.  char *lokfile;
  587.  /* Change to the spool directory */
  588.  if(chdir(Url->proto))
  589.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",Url->proto);return;}
  590.  if(chdir(Url->dir))
  591.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s].",Url->proto,Url->dir);chdir("..");return;}
  592.  /* Delete the file for the backup web page. */
  593.  lokfile=URLToFileName(Url);
  594.  *lokfile='L';
  595.  if(unlink(lokfile))
  596.     PrintMessage(Inform,"Cannot unlink lock file '%s/%s/%s' [%!s].",Url->proto,Url->dir,lokfile);
  597.  /* Change dir back and tidy up. */
  598.  chdir("../..");
  599.  free(lokfile);
  600. }
  601. /*++++++++++++++++++++++++++++++++++++++
  602.   Create a file in the lasttime directory.
  603.   int CreateLastTimeSpoolFile Returns 1 if the file already exists.
  604.   URL *Url The URL to create.
  605.   ++++++++++++++++++++++++++++++++++++++*/
  606. int CreateLastTimeSpoolFile(URL *Url)
  607. {
  608.  struct stat buf;
  609.  char *file;
  610.  int exists=0;
  611.  if(NoLasttimeIndex)
  612.     return(1);
  613.  /* Change to the last time directory */
  614.  if(chdir("lasttime"))
  615.    {PrintMessage(Warning,"Cannot change to directory 'lasttime' [%!s].");return(0);}
  616.  /* Create the file. */
  617.  file=URLToFileName(Url);
  618.  *file='D';
  619.  if(stat(file,&buf)==-1)
  620.    {
  621.     char *name=(char*)malloc(strlen(Url->proto)+strlen(Url->dir)+strlen(file)+8);
  622.     sprintf(name,"../%s/%s/%s",Url->proto,Url->dir,file);
  623.     if(link(name,file))
  624.       {PrintMessage(Warning,"Cannot create file 'lasttime/%s' [%!s].",file);}
  625.     else
  626.       {
  627.        *file='U';
  628.        sprintf(name,"../%s/%s/%s",Url->proto,Url->dir,file);
  629.        if(link(name,file))
  630.          {PrintMessage(Warning,"Cannot create file 'lasttime/%s' [%!s].",file);}
  631.       }
  632.     free(name);
  633.    }
  634.  else
  635.     exists=1;
  636.  /* Change dir back and tidy up. */
  637.  chdir("..");
  638.  free(file);
  639.  return(exists);
  640. }
  641. /*++++++++++++++++++++++++++++++++++++++
  642.   Determine if a particular URL exists in the last time spool directory.
  643.   int ExistsLastTimeSpoolFile Returns 1 if the URL exists.
  644.   URL *Url The URL to look for.
  645.   ++++++++++++++++++++++++++++++++++++++*/
  646. int ExistsLastTimeSpoolFile(URL *Url)
  647. {
  648.  struct stat buf;
  649.  int i,retval=0;
  650.  char *name=URLToFileName(Url);
  651.  *name='D';
  652.  for(i=0;i<=NUM_PREVTIME_DIR;i++)
  653.    {
  654.     char lasttime[40];
  655.     if(i)
  656.        sprintf(lasttime,"prevtime%d/%s",i,name);
  657.     else
  658.        sprintf(lasttime,"lasttime/%s",name);
  659.     if(!stat(lasttime,&buf))
  660.       {retval=1;break;}
  661.    }
  662.  free(name);
  663.  return(retval);
  664. }
  665. /*++++++++++++++++++++++++++++++++++++++
  666.   Delete a specified URL from the lasttime directory.
  667.   char *DeleteLastTimeSpoolFile Returns NULL if OK else error message.
  668.   URL *Url The URL to delete or NULL for all of them.
  669.   ++++++++++++++++++++++++++++++++++++++*/
  670. char *DeleteLastTimeSpoolFile(URL *Url)
  671. {
  672.  struct stat buf;
  673.  char *err=NULL;
  674.  int i;
  675.  char *name=URLToFileName(Url);
  676.  for(i=0;i<=NUM_PREVTIME_DIR;i++)
  677.    {
  678.     char lasttime[16];
  679.     if(i)
  680.        sprintf(lasttime,"prevtime%d",i);
  681.     else
  682.        strcpy(lasttime,"lasttime");
  683.     /* Change to the last time directory */
  684.     if(chdir(lasttime))
  685.       {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",lasttime);}
  686.     else
  687.       {
  688.        *name='D';
  689.        if(!stat(name,&buf))
  690.          {
  691.           if(unlink(name))
  692.              err=PrintMessage(Warning,"Cannot unlink lasttime request '%s/%s' [%!s].",lasttime,name);
  693.           *name='U';
  694.           unlink(name);
  695.          }
  696.        chdir("..");
  697.       }
  698.    }
  699.  free(name);
  700.  return(err);
  701. }
  702. /*++++++++++++++++++++++++++++++++++++++
  703.   Cycle the URLs from the lasttime directory down to the prevtime directories.
  704.   ++++++++++++++++++++++++++++++++++++++*/
  705. void CycleLastTimeSpoolFile(void)
  706. {
  707.  char lasttime[16],prevlasttime[16];
  708.  struct stat buf;
  709.  int i;
  710.  /* Cycle the directories */
  711.  for(i=NUM_PREVTIME_DIR;i>=0;i--)
  712.    {
  713.     if(i)
  714.        sprintf(lasttime,"prevtime%d",i);
  715.     else
  716.        strcpy(lasttime,"lasttime");
  717.     /* Create it if it does not exist. */
  718.     if(lstat(lasttime,&buf))
  719.       {
  720.        PrintMessage(Inform,"Directory '%s' does not exist [%!s]; creating one.",lasttime);
  721.        if(mkdir(lasttime,DirPerm))
  722.           PrintMessage(Warning,"Cannot create directory '%s' [%!s].",lasttime);
  723.       }
  724.     else
  725.        if(!S_ISDIR(buf.st_mode))
  726.           PrintMessage(Warning,"The file '%s' is not a directory.",lasttime);
  727.     /* Delete the contents of the oldest one, rename the newer ones. */
  728.     if(i==NUM_PREVTIME_DIR)
  729.       {
  730.        DIR *dir;
  731.        struct dirent* ent;
  732.        if(chdir(lasttime))
  733.          {PrintMessage(Warning,"Cannot change to directory '%s' [%!s].",lasttime);continue;}
  734.        dir=opendir(".");
  735.        if(!dir)
  736.          {PrintMessage(Warning,"Cannot open current directory '%s' [%!s].",lasttime);chdir("..");continue;}
  737.        ent=readdir(dir);  /* skip .  */
  738.        if(!ent)
  739.          {PrintMessage(Warning,"Cannot read current directory '%s' [%!s].",lasttime);closedir(dir);chdir("..");continue;}
  740.        ent=readdir(dir);  /* skip .. */
  741.        while((ent=readdir(dir)))
  742.           if(unlink(ent->d_name))
  743.              PrintMessage(Warning,"Cannot unlink previous time page '%s/%s' [%!s].",lasttime,ent->d_name);
  744.        closedir(dir);
  745.        chdir("..");
  746.        if(rmdir(lasttime))
  747.           PrintMessage(Warning,"Cannot unlink previous time directory '%s' [%!s].",lasttime);
  748.       }
  749.     else
  750.        if(rename(lasttime,prevlasttime))
  751.           PrintMessage(Warning,"Cannot rename previous time directory '%s' to '%s' [%!s].",lasttime,prevlasttime);
  752.     strcpy(prevlasttime,lasttime);
  753.    }
  754.  if(mkdir("lasttime",DirPerm))
  755.     PrintMessage(Warning,"Cannot create directory 'lasttime' [%!s].");
  756. }
  757. /*++++++++++++++++++++++++++++++++++++++
  758.   Open a file in the monitor directory to write into.
  759.   int CreateMonitorSpoolFile Returns a file descriptor, or -1 on failure.
  760.   URL *Url The URL of the file to monitor.
  761.   char MofY[13] A mask indicating the months of the year allowed.
  762.   char DofM[32] A mask indicating the days of the month allowed.
  763.   char DofW[8] A mask indicating the days of the week allowed.
  764.   char HofD[25] A mask indicating the hours of the day allowed.
  765.   ++++++++++++++++++++++++++++++++++++++*/
  766. int CreateMonitorSpoolFile(URL *Url,char MofY[13],char DofM[32],char DofW[8],char HofD[25])
  767. {
  768.  struct stat buf;
  769.  int fd=-1;
  770.  char *file;
  771.  /* Create the monitor directory if needed and change to it */
  772.  if(lstat("monitor",&buf))
  773.    {
  774.     PrintMessage(Inform,"Directory 'monitor' does not exist [%!s]; creating one.");
  775.     if(mkdir("monitor",DirPerm))
  776.       {PrintMessage(Warning,"Cannot create directory 'monitor' [%!s].");return(-1);}
  777.    }
  778.  else
  779.     if(!S_ISDIR(buf.st_mode))
  780.       {PrintMessage(Warning,"The file 'monitor' is not a directory.");return(-1);}
  781.  if(chdir("monitor"))
  782.    {PrintMessage(Warning,"Cannot change to directory 'monitor' [%!s].");return(-1);}
  783.  /* Open the monitor file */
  784.  file=URLToFileName(Url);
  785.  *file='O';
  786.  fd=open(file,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,FilePerm);
  787.  if(fd==-1)
  788.    {PrintMessage(Warning,"Cannot create file 'monitor/%s' [%!s].",file);}
  789.  else
  790.    {
  791.     int ufd,mfd;
  792.     *file='U';
  793.     ufd=open(file,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,FilePerm);
  794.     if(ufd!=-1)
  795.       {
  796.        write_string(ufd,Url->file);
  797.        close(ufd);
  798.       }
  799.     else
  800.       {
  801.        close(fd);
  802.        fd=-1;
  803.       }
  804.     *file='M';
  805.     mfd=open(file,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,FilePerm);
  806.     if(mfd!=-1)
  807.       {
  808.        write_formatted(mfd,"%sn",MofY);
  809.        write_formatted(mfd,"%sn",DofM);
  810.        write_formatted(mfd,"%sn",DofW);
  811.        write_formatted(mfd,"%sn",HofD);
  812.        close(mfd);
  813.       }
  814.     else
  815.       {
  816.        close(fd);
  817.        fd=-1;
  818.       }
  819.    }
  820.  /* Change dir back and tidy up. */
  821.  chdir("..");
  822.  free(file);
  823.  return(fd);
  824. }
  825. /*++++++++++++++++++++++++++++++++++++++
  826.   Read a file containing the time to be monitored.
  827.   long ReadMonitorTimesSpoolFile Returns the timestamp of the file.
  828.   URL *Url The URL to read from.
  829.   char MofY[13] Returns a mask indicating the months of the year allowed.
  830.   char DofM[32] Returns a mask indicating the days of the month allowed.
  831.   char DofW[8] Returns a mask indicating the days of the week allowed.
  832.   char HofD[25] Returns a mask indicating the hours of the day allowed.
  833.   ++++++++++++++++++++++++++++++++++++++*/
  834. long ReadMonitorTimesSpoolFile(URL *Url,char MofY[13],char DofM[32],char DofW[8],char HofD[25])
  835. {
  836.  time_t atime,mtime;
  837.  struct stat buf;
  838.  int mfd;
  839.  char *file;
  840.  strcpy(MofY,"111111111111");
  841.  strcpy(DofM,"1111111111111111111111111111111");
  842.  strcpy(DofW,"1111111");
  843.  strcpy(HofD,"100000000000000000000000");
  844.  /* Change to the monitor directory. */
  845.  if(chdir("monitor"))
  846.    {PrintMessage(Warning,"Cannot change to directory 'monitor' [%!s].");return(0);}
  847.  file=URLToFileName(Url);
  848.  /* Check for 'O*' file. */
  849.  *file='O';
  850.  if(lstat(file,&buf))
  851.     atime=0,mtime=time(NULL);
  852.  else
  853.     atime=buf.st_atime,mtime=buf.st_mtime;
  854.  /* Check for 'M*' file for the old format. */
  855.  *file='M';
  856.  if(lstat(file,&buf) || buf.st_size<8)
  857.    {
  858.     int interval=7;
  859.     mfd=open(file,O_RDONLY|O_BINARY);
  860.     if(mfd)
  861.       {
  862.        char str[8];
  863.        if(read(mfd,str,8)>0)
  864.           interval=atoi(str);
  865.        if(interval<0)
  866.           interval=0;
  867.        close(mfd);
  868.       }
  869.     strcpy(MofY,"111111111111");
  870.     if(interval==7)
  871.       {
  872.        strcpy(DofM,"1111111111111111111111111111111");
  873.        strcpy(DofW,"0000000"); DofW[(4+mtime/(3600*24))%7]='1';
  874.       }
  875.     else
  876.       {
  877.        int i;
  878.        if(interval)
  879.          {strcpy(DofM,"0000000000000000000000000000000"); for(i=0;i<31;i+=interval) DofM[i]='1';}
  880.        else
  881.           strcpy(DofM,"1111111111111111111111111111111");
  882.        strcpy(DofW,"1111111");
  883.       }
  884.     if(interval)
  885.       {strcpy(HofD,"000000000000000000000000"); HofD[(mtime/3600)%24]='1';}
  886.     else
  887.        strcpy(HofD,"111111111111111111111111");
  888.     chdir("..");
  889.     return(atime);
  890.    }
  891.  /* Assume that the file is in the new format. */
  892.  mfd=open(file,O_RDONLY|O_BINARY);
  893.  if(mfd)
  894.    {
  895.     char line[80];
  896.     line[78]=0;
  897.     if(read(mfd,line,80)!=78 ||
  898.        sscanf(line,"%12s %31s %7s %24s",MofY,DofM,DofW,HofD)!=4 ||
  899.        strlen(MofY)!=12 || strlen(DofM)!=31 || strlen(DofW)!=7 || strlen(HofD)!=24)
  900.       {
  901.        strcpy(MofY,"111111111111");
  902.        strcpy(DofM,"1111111111111111111111111111111");
  903.        strcpy(DofW,"1111111");
  904.        strcpy(HofD,"100000000000000000000000");
  905.       }
  906.     close(mfd);
  907.    }
  908.  chdir("..");
  909.  return(atime);
  910. }
  911. /*++++++++++++++++++++++++++++++++++++++
  912.   Delete a specified URL from the monitor directory.
  913.   char *DeleteMonitorSpoolFile Returns NULL if OK else error message.
  914.   URL *Url The URL to delete or NULL for all of them.
  915.   ++++++++++++++++++++++++++++++++++++++*/
  916. char *DeleteMonitorSpoolFile(URL *Url)
  917. {
  918.  char *err=NULL;
  919.  char *name;
  920.  /* Change to the monitor directory. */
  921.  if(chdir("monitor"))
  922.    {err=PrintMessage(Warning,"Cannot change to directory 'monitor' [%!s].");return(err);}
  923.  /* Delete the file for the request. */
  924.  if(Url)
  925.    {
  926.     name=URLToFileName(Url);
  927.     *name='O';
  928.     if(unlink(name))
  929.        err=PrintMessage(Warning,"Cannot unlink monitor request 'monitor/%s' [%!s].",name);
  930.     *name='U';
  931.     unlink(name);
  932.     *name='M';
  933.     unlink(name);
  934.     free(name);
  935.    }
  936.  else
  937.    {
  938.     struct dirent* ent;
  939.     DIR *dir=opendir(".");
  940.     if(!dir)
  941.       {err=PrintMessage(Warning,"Cannot open current directory 'monitor' [%!s].");chdir("..");return(err);}
  942.     ent=readdir(dir);  /* skip .  */
  943.     if(!ent)
  944.       {err=PrintMessage(Warning,"Cannot read current directory 'monitor' [%!s].");closedir(dir);chdir("..");return(err);}
  945.     ent=readdir(dir);  /* skip .. */
  946.     while((ent=readdir(dir)))
  947.       {
  948.        if(unlink(ent->d_name))
  949.           err=PrintMessage(Warning,"Cannot unlink outgoing request 'monitor/%s' [%!s].",ent->d_name);
  950.       }
  951.     closedir(dir);
  952.    }
  953.  /* Change dir back and tidy up. */
  954.  chdir("..");
  955.  return(err);
  956. }
  957. /*++++++++++++++++++++++++++++++++++++++
  958.   Create a temporary spool file.
  959.   int CreateTempSpoolFile Returns the file descriptor.
  960.   ++++++++++++++++++++++++++++++++++++++*/
  961. int CreateTempSpoolFile(void)
  962. {
  963.  char name[16];
  964.  struct stat buf;
  965.  int fd;
  966.  /* Create the outgoing directory if needed and change to it */
  967.  if(lstat("temp",&buf))
  968.    {
  969.     PrintMessage(Inform,"Directory 'temp' does not exist [%!s]; creating one.");
  970.     if(mkdir("temp",DirPerm))
  971.       {PrintMessage(Warning,"Cannot create directory 'temp' [%!s].");return(-1);}
  972.    }
  973.  else
  974.     if(!S_ISDIR(buf.st_mode))
  975.       {PrintMessage(Warning,"The file 'temp' is not a directory.");return(-1);}
  976.  /* Open the file */
  977.  sprintf(name,"temp/tmp.%ld",(long)getpid());
  978.  fd=open(name,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,FilePerm);
  979.  if(fd==-1)
  980.     PrintMessage(Warning,"Cannot create temporary file '%s' [%!s].",name);
  981.  return(fd);
  982. }
  983. /*++++++++++++++++++++++++++++++++++++++
  984.   Close and delete the temporary spool file.
  985.   int fd The file descriptor.
  986.   ++++++++++++++++++++++++++++++++++++++*/
  987. void CloseTempSpoolFile(int fd)
  988. {
  989.  char name[16];
  990.  sprintf(name,"temp/tmp.%ld",(long)getpid());
  991.  if(unlink(name)==-1)
  992.     PrintMessage(Warning,"Cannot unlink temporary file '%s' [%!s].",name);
  993.  close(fd);
  994. }
  995. /*++++++++++++++++++++++++++++++++++++++
  996.   Convert a filename to a URL.
  997.   char *FileNameToURL Returns the URL.
  998.   char *file The file name.
  999.   ++++++++++++++++++++++++++++++++++++++*/
  1000. char *FileNameToURL(char *file)
  1001. {
  1002.  char *path,*copy;
  1003.  int ufd,r;
  1004.  if(!file || !*file)
  1005.     return(NULL);
  1006.  copy=(char*)malloc(strlen(file)+1);
  1007.  strcpy(copy,file);
  1008.  path=(char*)malloc(256+1);
  1009.  *copy='U';
  1010.  ufd=open(copy,O_RDONLY|O_BINARY);
  1011.  if(ufd==-1)
  1012.    {
  1013.     free(copy);
  1014.     free(path);
  1015.     return(NULL);
  1016.    }
  1017.  r=read(ufd,path,256);
  1018.  if(r==256)
  1019.    {
  1020.     int rr=0;
  1021.     do
  1022.       {
  1023.        r+=rr;
  1024.        path=(char*)realloc(path,r+256+1);
  1025.       }
  1026.     while((rr=read(ufd,&path[r],256))>0);
  1027.    }
  1028.  else if(r==-1)
  1029.    {
  1030.     close(ufd);
  1031.     free(copy);
  1032.     free(path);
  1033.     return(NULL);
  1034.    }
  1035.  path[r]=0;
  1036.  close(ufd);
  1037.  free(copy);
  1038.  return(path);
  1039. }
  1040. /*++++++++++++++++++++++++++++++++++++++
  1041.   Convert a URL to a filename
  1042.   char *URLToFileName Returns the filename.
  1043.   URL *Url The URL to convert to a filename.
  1044.   ++++++++++++++++++++++++++++++++++++++*/
  1045. char *URLToFileName(URL *Url)
  1046. {
  1047.  char *hash;
  1048.  char *file;
  1049.  hash=MakeHash(Url->file);
  1050.  file=(char*)malloc(strlen(hash)+3);
  1051.  sprintf(file,"X%s",hash);
  1052.  return(file);
  1053. }