Logo Search packages:      
Sourcecode: jftpgw version File versions  Download package

cache.c

/* 
 * Copyright (C) 1999-2004 Joachim Wieland <joe@mcknight.de>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111, USA.
 */

#include "jftpgw.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <utime.h>

#define INFO_SUFFIX ".info"

extern struct hostent_list* hostcache;

/* only the user should be able to read/write the cache */
int cache_perms = S_IRWXU;

int cache_available(struct cache_filestruct);
int cache_readinfo(struct cache_filestruct*);
int cache_writeinfo(struct cache_filestruct);
int cache_want(struct cache_filestruct);
char* cache_qualifypath(const struct cache_filestruct);
char* cache_qualifyfile(const struct cache_filestruct);
char* cache_qualifyinfo(const struct cache_filestruct);
int recursive_mkdir(const char* pathname, int perms);


struct cache_filestruct cache_gather_info(const char* filename,
                                    struct clientinfo* clntinfo) {
      char* pwd;
      char* complete_fname;
      size_t size;
      struct cache_filestruct cfs;

      if (filename[0] != '/') {
            /* get the directory */
            pwd = getftpwd(clntinfo);
      } else {
            pwd = strdup("");
            enough_mem(pwd);
      }
      size = strlen(filename) + 1 + strlen(pwd) + 1;
      complete_fname = (char*) malloc(size);
      enough_mem(complete_fname);
      complete_fname = rel2abs(filename, pwd, complete_fname, size);
      if ((char*) 0 == complete_fname) {
            jlog(4, "Error in rel2abs: filename: %s, path: %s",
                        filename, pwd);
      }
      free(pwd);
      cfs.filepath = extract_path(complete_fname);
      cfs.filename = extract_file(complete_fname);
      cfs.size = getftpsize(complete_fname, clntinfo);
      cfs.date = getftpmdtm(complete_fname, clntinfo);
      free(complete_fname);
      /* filename is not free()ed, it points inside args and thus inside
       * buffer in cmds.c */

      cfs.user = clntinfo->user;
      cfs.host = clntinfo->destination;
      cfs.port = clntinfo->destinationport;

      return cfs;
}

int cache_available(struct cache_filestruct cfs) {
      char* fname = cache_qualifyfile(cfs);
      struct cache_filestruct cfs_info;
      struct stat st;

      if (stat(fname, &st) < 0) {
            if (errno == ENOENT) {
                  return CACHE_NOTAVL_EXIST;
            }
            /* other error */
            jlog(2, "Could not stat %s: %s",
                        fname, strerror(errno));
            return -1;
      }

      if (cfs.size != st.st_size) {
            /* the new file seems to differ in size -> delete our copy
             * */
            jlog(8, "cache copy differs in size");
            cache_delete(cfs, 1);
            return CACHE_NOTAVL_SIZE;
      }

      if (cfs.date != st.st_mtime) {
            /* the new file seems to differ in the date -> delete our
             * copy */
            jlog(8, "cache copy differs in the date");
            cache_delete(cfs, 1);
            return CACHE_NOTAVL_DATE;
      }

      cfs_info = cfs;
      cache_readinfo(&cfs_info);

      if (cfs.checksum != cfs_info.checksum) {
            /* the new file seems to differ in the checksum -> delete
             * our copy */
            cache_delete(cfs, 1);
            return CACHE_NOTAVL_CHECKSUM;
      }

      return CACHE_AVAILABLE;
}


int cache_add(struct cache_filestruct cfs) {

      struct stat st;
      char* fname = cache_qualifyfile(cfs);
      struct utimbuf ut;

      /* okay, we're sure the path exists, let's try to create a file */

      /* compare size, set date... */

      if (stat(fname, &st) < 0) {
            jlog(2, "Could not stat %s: %s",
                        fname, strerror(errno));
            return -1;
      }
      if (st.st_size != cfs.size) {
            jlog(6, "Had to delete %s again. Size did not match", fname);
            cache_delete(cfs, 1);
      }

      /* set the date */
      ut.actime = ut.modtime = cfs.date;
      if (utime(fname, &ut) < 0) {
            jlog(6, "Could net set date/time information to %s: %s",
                        fname, strerror(errno));
      }

      return cache_writeinfo(cfs);

}

int cache_writefd(struct cache_filestruct cfs) {
/*
      Add a file to the cache.

      The directory structure is like

      <cache_prefix> / <user>@<host>:<port> / <filepath> / <filename>
*/
      char* path;
      char* filefn;
      int fd;

      if (!cache_want(cfs)) {
            return -1;
      }

      /* just delete for sure, don't care about the return value */
      cache_delete(cfs, 0);

      path = cache_qualifypath(cfs);
      if (recursive_mkdir(path, cache_perms) < 0 && errno != EEXIST) {
            jlog(2, "Could not create directory %s: %s",
                  path, strerror(errno));
            return -1;
      }

      filefn = cache_qualifyfile(cfs);
      fd = creat(filefn, cache_perms);
      if (fd < 0) {
            jlog(2, "Could not create data file %s in cache: %s",
                        filefn, strerror(errno));
      }
      return fd;
}

int cache_delete(struct cache_filestruct cfs, int warn) {
      char* infofile, *datafile;
      int err = 0;

      infofile = cache_qualifyinfo(cfs);
      datafile = cache_qualifyfile(cfs);

      /*if (unlink(infofile) < 0) {
            jlog(2, "Could not unlink file %s: %s",
                        infofile, strerror(errno));
            * do not return immediately, try to delete the other entry,
             * too *
            err = -1;
      }*/
      if (unlink(datafile) < 0 && warn) {
            jlog(2, "Could not unlink file %s: %s",
                        datafile, strerror(errno));
            err = -1;
      }
      return err;
}

int cache_readfd(struct cache_filestruct cfs) {
      char* fname = cache_qualifyfile(cfs);
      int fd;

      if (cache_available(cfs) != CACHE_AVAILABLE) {
            return -1;
      }

      fd = open(fname, O_RDONLY);
      return fd;
}

int cache_want(struct cache_filestruct cfs) {
/*
      See if we want a file to be added to the cache.
*/
      unsigned long int minsize = config_get_size("cacheminsize", 0);
      unsigned long int maxsize = config_get_size("cachemaxsize", ULONG_MAX);

      return (cfs.size <= maxsize && cfs.size >= minsize);
}

int cache_readinfo(struct cache_filestruct *cfs) {
      char* fname = cache_qualifyinfo(*cfs);
      char checksumbuf[128];
      int fdinfo;
      int i;

      return 0; /* not yet implemented */

      if (cfs->checksum) {
            free(cfs->checksum);
            cfs->checksum = (char*) 0;
      }

      fdinfo = open(fname, O_RDONLY);

      if (fdinfo < 0) {
            jlog(2, "Could not open file %s in cache: %s",
                        fname, strerror(errno));
            return -1;
      }

      /* file is opened */
      i = read(fdinfo, checksumbuf, sizeof(checksumbuf) - 1);
      if (i < 0) {
            jlog(3, "Could not read info from file %s: %s",
                        fname, strerror(errno));
            close(fdinfo);
            return -1;
      }

      if (i > 0 && i < sizeof(checksumbuf)) {
            checksumbuf[i] = '\0';
      }
      cfs->checksum = strdup(checksumbuf);
      close(fdinfo);
      return 0;
}


int cache_writeinfo(struct cache_filestruct cfs) {
      char* fname = cache_qualifyinfo(cfs);
      int fdinfo;
      int i;

      return 0; /* not yet implemented */

      fdinfo = creat(fname, cache_perms);
      if (fdinfo < 0) {
            jlog(2, "Could not create info file %s in cache: %s",
                        fname, strerror(errno));
            return -1;
      }

      /* file is created and opened */
      /* write the info */
      i = write(fdinfo, cfs.checksum, strlen(cfs.checksum));
      i += write(fdinfo, "\n", 1);

      close(fdinfo);

      if (i == strlen(cfs.checksum) + 1) {
            return 0;
      } else {
            return -1;
      }
}


char* cache_qualifypath(const struct cache_filestruct cfs) {
      size_t size;
      static char* path;
      const char* hostname;
      unsigned long iaddr;
      const char* cache_prefix = config_get_option("cacheprefix");

      if (!cache_prefix || config_get_bool("cache") == 0) {
            return (char*) 0;
      }
      iaddr = inet_addr(cfs.host);
      if (iaddr == (unsigned long int) UINT_MAX) {
            /* cfs.host was not a valid IP */
            hostname = cfs.host;
      } else {
            /* try to look it up */
            if ( !(hostname = hostent_get_name(&hostcache, iaddr)) ) {
                  hostname = cfs.host;
            }
      }

      size =        strlen(cache_prefix) + 1
                  + strlen(cfs.user)     + 1
                  + strlen(hostname)     + 1
                  + 20
                  + strlen(cfs.filepath) + 1
                  + 1;

      if (path) {
            path = (char*) realloc(path, size);
      } else {
            path = (char*) malloc(size);
      }
      enough_mem(path);

      snprintf(path, size, "%s/%s@%s:%d/%s",
                  cache_prefix,
                  cfs.user,
                  hostname,
                  cfs.port,
                  cfs.filepath);

      return path;
}


char* cache_qualifyfile(const struct cache_filestruct cfs) {
      char* path = cache_qualifypath(cfs);
      size_t size = strlen(path) + 1 + strlen(cfs.filename) + 1;
      static char* filename;

      if (filename) {
            filename = (char*) realloc(filename, size);
      } else {
            filename = (char*) malloc(size);
      }
      enough_mem(filename);

      snprintf(filename, size, "%s/%s", path, cfs.filename);

      return filename;
}


char* cache_qualifyinfo(const struct cache_filestruct cfs) {
      char* filename = cache_qualifyfile(cfs);
      size_t size = strlen(filename) + strlen(INFO_SUFFIX) + 1;
      static char* infoname;

      if (infoname) {
            infoname = (char*) realloc(infoname, size);
      } else {
            infoname = (char*) malloc(size);
      }
      enough_mem(infoname);

      snprintf(infoname, size, "%s/%s", filename, INFO_SUFFIX);

      return infoname;
}


int recursive_mkdir(const char* pathname, int perms) {
      char* tocreate;
      int sidx = 0;
      int failed = 0;

      tocreate = (char*) malloc(strlen(pathname) + 1);
      enough_mem(tocreate);

      do {
            while(pathname[sidx] && pathname[sidx] != '/') {
                  tocreate[sidx] = pathname[sidx];
                  sidx++;
            }
            tocreate[sidx] = pathname[sidx];
            sidx++;
            tocreate[sidx] = '\0';

            jlog(9, "Creating %s\n", tocreate);
            /* If the directory exists, Linux returns EEXIST whereas
             * *BSD (at least FreeBSD returns EISDIR */
            if (mkdir(tocreate, perms) < 0
                        && errno != EEXIST && errno != EISDIR) {
                  failed = -1;
            }
      } while(pathname[sidx] && failed == 0);

      free(tocreate);
      return -failed;
}


Generated by  Doxygen 1.6.0   Back to index