fscache.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:9k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** fscache.c
  3. **
  4. ** Copyright (c) 1995 Peter Eriksson <pen@signum.se>
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <sys/mman.h>
  25. #include <limits.h>
  26. #include <syslog.h>
  27. #include "phttpd.h"
  28. #ifndef MAP_FAILED
  29. #define MAP_FAILED ((caddr_t) -1)
  30. #endif
  31. #ifndef MAP_NORESERVE
  32. #define MAP_NORESERVE 0
  33. #endif
  34. int fscache_refresh = 30;
  35. int fscache_ttl = 120;
  36. int fscache_gc_interval = 120;
  37. int fscache_size = 101;
  38. static cache_t fscache;
  39. fsinfo_t *fsinfo_alloc(char *url,
  40.        char *path,
  41.        uid_t uid,
  42.        gid_t gid,
  43.        struct stat *sp)
  44. {
  45.     fsinfo_t *fip;
  46.     if (debug > 3)
  47. fprintf(stderr, "fsinfo_alloc("%s", "%s")n",
  48. url, path);
  49.     
  50.     fip = s_malloc(sizeof(fsinfo_t));
  51.     fip->url = s_strdup(url);
  52.     fip->path = s_strdup(path);
  53.     fip->uid = uid;
  54.     fip->gid = gid;
  55.     if (sp)
  56. fip->sb = *sp;
  57.     
  58.     mutex_init(&fip->data_lock, USYNC_THREAD, NULL);
  59.     return fip;
  60. }    
  61. void fsinfo_free(void *data)
  62. {
  63.     fsinfo_t *fip = data;
  64.     
  65.     if (debug > 2)
  66. fprintf(stderr, "fsinfo_free(), url=%s, path=%sn",
  67. fip->url, fip->path);
  68.     if (S_ISDIR(fip->sb.st_mode))
  69.     {
  70. struct fsc_dirent *fdp, *next;
  71. fdp = fip->data.dir.head;
  72. while (fdp)
  73. {
  74.     next = fdp->next;
  75.     if (fdp->fep)
  76. fscache_release(fdp->fep);
  77.     
  78.     s_free(fdp->dbp);
  79.     s_free(fdp);
  80.     fdp = next;
  81. }
  82.     }
  83.     else if (S_ISREG(fip->sb.st_mode))
  84.     {
  85. if (fip->data.file.content)
  86.     munmap(fip->data.file.content, fip->sb.st_size);
  87.     }
  88.     if (fip->url)
  89. s_free(fip->url);
  90.     
  91.     if (fip->path)
  92. s_free(fip->path);
  93.     
  94.     s_free(fip);
  95. }
  96. static int fsinfo_loaddir(fsinfo_t *fip)
  97. {
  98.     S_DIR *dp;
  99.     struct dirent *dbp;
  100.     struct fsc_dirent *fdp, **prev;
  101.     char buf[2048], *ep, c;
  102.     struct stat sb;
  103.     
  104.     
  105.     if (debug > 2)
  106. fprintf(stderr, "fsinfo_loaddir(), url=%s, path=%sn",
  107. fip->url, fip->path);
  108.     s_strcpy(buf, sizeof(buf), fip->path);
  109.     s_strcat(buf, sizeof(buf), "/.nodir");
  110.       
  111.     if (s_stat(buf, &sb) == 0)
  112.     {
  113. if (debug > 2)
  114.     fprintf(stderr, "fsinfo_loaddir(): denied ('.nodir' exists)n");
  115. return -1;
  116.     }
  117.     
  118.     dp = s_opendir(fip->path);
  119.     if (dp == NULL)
  120.     {
  121. if (debug > 2)
  122.     fprintf(stderr, "fsinfo_loaddir(), failing (opendir)n");
  123. return -1;
  124.     }
  125.     s_strcpy(buf, sizeof(buf), fip->url);
  126.     
  127.     c = 0;
  128.     for (ep = buf; *ep; ep++)
  129. c = *ep;
  130.     if (c != '/')
  131. *ep++ = '/';
  132.     prev = &fip->data.dir.head;
  133.     while ((dbp = s_readdir(dp)) != NULL)
  134.     {
  135. if (debug > 2)
  136.     fprintf(stderr, "fsinfo_loaddir(), entry=%s, reclen=%dn",
  137.     dbp->d_name, dbp->d_reclen);
  138. if (strcmp(dbp->d_name, ".") == 0 ||
  139.     strcmp(dbp->d_name, "..") == 0)
  140.     continue;
  141. fip->data.dir.size++;
  142. fdp = s_malloc(sizeof(struct fsc_dirent));
  143. fdp->dbp = dbp;
  144. s_strcpy(ep, sizeof(buf)-(ep-buf), dbp->d_name);
  145. fdp->fep = fscache_lookup(buf, 0);
  146. *prev = fdp;
  147. prev = &fdp->next;
  148.     }
  149.     s_free(dbp);
  150.     s_closedir(dp);
  151.     
  152.     fip->data_avail = 1;
  153.     return 0;
  154. }
  155. static int fsinfo_loadfile(fsinfo_t *fip)
  156. {
  157.     int fd;
  158.     fd = s_open(fip->path, O_RDONLY);
  159.     if (fd < 0)
  160.     {
  161. if (debug > 1)
  162.     fprintf(stderr, "fsinfo_loadfile(): s_open("%s") failed: %dn",
  163.     fip->path, errno);
  164. return -1;
  165.     }
  166.     
  167.     if (fstat(fd, &fip->sb) < 0)
  168.     {
  169. if (debug > 1)
  170.     fprintf(stderr, "fsinfo_loadfile(): fstat("%s") failed: %dn",
  171.     fip->path, errno);
  172. s_close(fd);
  173. return -1;
  174.     }
  175.     if (!S_ISREG(fip->sb.st_mode))
  176.     {
  177. s_close(fd);
  178. if (debug > 1)
  179.     fprintf(stderr, "fsinfo_loadfile(): not regular file: %sn",
  180.     fip->path);
  181. return -1;
  182.     }
  183.     if (fip->sb.st_size > 0)
  184.     {
  185. fip->data.file.content = mmap((caddr_t) NULL,
  186.       fip->sb.st_size,
  187.       PROT_READ,
  188.       MAP_PRIVATE+MAP_NORESERVE,
  189.       fd, 0);
  190.     
  191. s_close(fd);
  192. if (fip->data.file.content == MAP_FAILED)
  193. {
  194.     if (debug > 1)
  195. fprintf(stderr, "fsinfo_loadfile(): mmap("%s") failed: %dn",
  196. fip->path, errno);
  197.     fip->data.file.content = NULL;
  198.     return -1;
  199. }
  200. madvise(fip->data.file.content,
  201. fip->sb.st_size,
  202. MADV_SEQUENTIAL);
  203. madvise(fip->data.file.content,
  204. fip->sb.st_size,
  205. MADV_WILLNEED);
  206.     }
  207.     else
  208. s_close(fd);
  209.     fip->data_avail = 1;
  210.     return 0;
  211. }
  212. static fsinfo_t *fsinfo_load(char *url,
  213.      char *path,
  214.      uid_t uid,
  215.      gid_t gid,
  216.      struct stat *sbp,
  217.      unsigned int flags)
  218. {
  219.     fsinfo_t *fip;
  220.     
  221.     if (debug > 2)
  222. fprintf(stderr, "fsinfo_load(), url=%s, path=%s, sbp=%08xn",
  223. url, path, (unsigned int) sbp);
  224.     fip = fsinfo_alloc(url, path, uid, gid, sbp);
  225.     if (fip == NULL)
  226.     {
  227. if (debug > 2)
  228.     fprintf(stderr, "fip == NULLn");
  229. return NULL;
  230.     }
  231.     
  232.     if (sbp == NULL)
  233.     {
  234. if (s_stat(path, &fip->sb) < 0)
  235. {
  236.     fsinfo_free(fip);
  237.     return NULL;
  238. }
  239. sbp = &fip->sb;
  240.     }
  241.     else
  242. fip->sb = *sbp;
  243.     
  244.     if (!(flags & FSCF_GETDATA))
  245. return fip;
  246.     if (S_ISDIR(sbp->st_mode))
  247.     {
  248. if (fsinfo_loaddir(fip) == -1)
  249. {
  250.     fsinfo_free(fip);
  251.     return NULL;
  252. }
  253.     }
  254.     else if (S_ISREG(sbp->st_mode))
  255. if (fsinfo_loadfile(fip) == -1)
  256. {
  257.     fsinfo_free(fip);
  258.     return NULL;
  259. }
  260.     return fip;
  261. }
  262. static int equal_stat(struct stat *s1,
  263.       struct stat *s2)
  264. {
  265.     return (s1->st_size == s2->st_size &&
  266.     s1->st_mtime == s2->st_mtime &&
  267.     s1->st_ino == s2->st_ino);
  268. }
  269. static int fsinfo_update(void *key,
  270.  unsigned int keylen,
  271.  void *data,
  272.  void **new_data,
  273.  void *misc)
  274. {
  275.     uid_t uid;
  276.     gid_t gid;
  277.     char path[2048];
  278.     struct stat sb;
  279.     char *url;
  280.     fsinfo_t *fip;
  281.     unsigned int flags;
  282.     flags = (misc ? *(unsigned int *)misc : 0);
  283.     if (debug > 2)
  284. fprintf(stderr, "fsinfo_update(), key=%s, flags=%dn",
  285. (char *) key,
  286. flags);
  287.     
  288.     url = key;
  289.     fip = data;
  290.     uid = gid = -1;
  291.     
  292.     if (fip == NULL)
  293.     {
  294. /* First time request */
  295. if (debug > 2)
  296.     fprintf(stderr, "fsinfo_update(): New cache entryn");
  297. if (url_expand(url, path, sizeof(path), NULL, &uid, &gid) == NULL)
  298. {
  299.     if (debug > 2)
  300. fprintf(stderr, "fsinfo_update(): Failed expandingn");
  301.     *new_data = NULL;
  302.     return 1;
  303. }
  304. if (debug > 2)
  305.     fprintf(stderr, "fsinfo_update(): Loading...n");
  306. *new_data = fsinfo_load(url, path, uid, gid, NULL, flags);
  307. return 1;
  308.     }
  309.     
  310.     if (s_stat(fip->path, &sb) < 0)
  311.     {
  312. if (debug > 2)
  313.     perror("fscache_update(): s_stat()");
  314. *new_data = NULL;
  315. return 1;
  316.     }
  317.     if (equal_stat(&sb, &fip->sb))
  318.     {
  319. /* File hasn't changed since last fstat() */
  320. if (debug > 2)
  321.     fprintf(stderr, "fscache_update(): File hasn't changedn");
  322. return 0;
  323.     }
  324.     if (debug > 2)
  325. fprintf(stderr, "fsinfo_update(): Loading (with stat)...n");
  326.     
  327.     *new_data = fsinfo_load(fip->url, fip->path, uid, gid, &sb, flags);
  328.     return 1;
  329. }    
  330. void fscache_init(void)
  331. {
  332.     cache_init(&fscache,
  333.        fscache_refresh, fscache_ttl, fscache_gc_interval,
  334.        fscache_size, NULL, fsinfo_free, fsinfo_update);
  335. }
  336. fscentry_t *fscache_lookup(char *url,
  337.    unsigned int flags)
  338. {
  339.     cacheentry_t *cep;
  340.     fscentry_t *fep;
  341.     
  342.     if (debug > 2)
  343. fprintf(stderr, "fscache_lookup("%s", %u)n", url, flags);
  344.     cep = cache_lookup(&fscache, url, 0, NULL,
  345.        ((flags & FSCF_RELOAD) ? CF_RELOAD : 0));
  346.     if (cep == NULL)
  347. return NULL;
  348.     fep = s_malloc(sizeof(fscentry_t));
  349.     
  350.     fep->cep = cep;
  351.     fep->fip = cep->data;
  352.     if (flags & FSCF_GETDATA)
  353. if (fscache_getdata(fep) != 1)
  354. {
  355.     fscache_release(fep);
  356.     return NULL;
  357. }
  358.     
  359.     return fep;
  360. }
  361. void fscache_release(fscentry_t *fep)
  362. {
  363.     if (fep == NULL)
  364. return;
  365.     
  366.     cache_release(fep->cep);
  367.     s_free(fep);
  368. }
  369. int fscache_getdata(fscentry_t *fep)
  370. {
  371.     fsinfo_t *fip;
  372.     
  373.     if (fep == NULL)
  374. return -1;
  375.     
  376.     fip = fep->fip;
  377.     if (fip == NULL)
  378. return -1;
  379.     
  380.     mutex_lock(&fip->data_lock);
  381.     if (fip->data_avail == 1)
  382.     {
  383. mutex_unlock(&fip->data_lock);
  384. return 1;
  385.     }
  386.     /* Load data */
  387.     if (S_ISREG(fip->sb.st_mode))
  388. fsinfo_loadfile(fip);
  389.     else if (S_ISDIR(fip->sb.st_mode))
  390. fsinfo_loaddir(fip);
  391.     mutex_unlock(&fip->data_lock);
  392.     return fip->data_avail == 1;
  393. }
  394. int fscache_getstats(cachestat_t *csp)
  395. {
  396.     return cache_getstats(&fscache, csp);
  397. }