varnish-cache/lib/libvmod_std/vmod_std_fileread.c
1
/*-
2
 * Copyright (c) 2010-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Sanjoy Das <sanjoy@playingwithpointers.com>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * XXX: It might make sense to use just a single global list of all files
29
 * XXX: and use the call-private pointer to point to the file instance on
30
 * XXX: that list.
31
 * XXX: Duplicates in the global list can be avoided by examining the
32
 * XXX: dev+inode fields of the stat structure.
33
 * XXX: Individual files would need to be refcounted, so they can be
34
 * XXX: deleted when no VCL's reference them.
35
 *
36
 * XXX: We should periodically stat(2) the filename and check if the
37
 * XXX: underlying file has been updated.
38
 */
39
40
#include "config.h"
41
42
#include <stdlib.h>
43
#include <string.h>
44
45
#include "cache/cache.h"
46
47
#include "vfil.h"
48
49
#include "vcc_if.h"
50
51
struct frfile {
52
        unsigned                        magic;
53
#define CACHED_FILE_MAGIC 0xa8e9d87a
54
        char                            *file_name;
55
        char                            *contents;
56
        int                             refcount;
57
        VTAILQ_ENTRY(frfile)            list;
58
};
59
60
static VTAILQ_HEAD(, frfile)    frlist = VTAILQ_HEAD_INITIALIZER(frlist);
61
static pthread_mutex_t          frmtx = PTHREAD_MUTEX_INITIALIZER;
62
63
static void
64 3
free_frfile(void *ptr)
65
{
66
        struct frfile *frf;
67
68 3
        CAST_OBJ_NOTNULL(frf, ptr, CACHED_FILE_MAGIC);
69
70 3
        AZ(pthread_mutex_lock(&frmtx));
71 3
        if (--frf->refcount > 0)
72 3
                frf = NULL;
73
        else
74 0
                VTAILQ_REMOVE(&frlist, frf, list);
75 3
        AZ(pthread_mutex_unlock(&frmtx));
76 3
        if (frf != NULL) {
77 0
                free(frf->contents);
78 0
                free(frf->file_name);
79 0
                FREE_OBJ(frf);
80
        }
81 3
}
82
83
VCL_STRING v_matchproto_(td_std_fileread)
84 18
vmod_fileread(VRT_CTX, struct vmod_priv *priv,
85
    VCL_STRING file_name)
86
{
87 18
        struct frfile *frf = NULL;
88
        char *s;
89
90 18
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
91 18
        AN(priv);
92
93 18
        if (priv->priv != NULL) {
94 11
                CAST_OBJ_NOTNULL(frf, priv->priv, CACHED_FILE_MAGIC);
95 11
                if (!strcmp(file_name, frf->file_name))
96 3
                        return (frf->contents);
97
        }
98
99 15
        AZ(pthread_mutex_lock(&frmtx));
100 15
        if (frf != NULL)
101 8
                frf->refcount--;
102 30
        VTAILQ_FOREACH(frf, &frlist, list) {
103 24
                if (!strcmp(file_name, frf->file_name)) {
104 9
                        frf->refcount++;
105 9
                        break;
106
                }
107
        }
108 15
        AZ(pthread_mutex_unlock(&frmtx));
109 15
        if (frf != NULL) {
110 9
                priv->free = free_frfile;
111 9
                priv->priv = frf;
112 9
                return (frf->contents);
113
        }
114
115 6
        s = VFIL_readfile(NULL, file_name, NULL);
116 6
        if (s != NULL) {
117 6
                ALLOC_OBJ(frf, CACHED_FILE_MAGIC);
118 6
                AN(frf);
119 6
                frf->file_name = strdup(file_name);
120 6
                AN(frf->file_name);
121 6
                frf->refcount = 1;
122 6
                frf->contents = s;
123 6
                priv->free = free_frfile;
124 6
                priv->priv = frf;
125 6
                AZ(pthread_mutex_lock(&frmtx));
126 6
                VTAILQ_INSERT_HEAD(&frlist, frf, list);
127 6
                AZ(pthread_mutex_unlock(&frmtx));
128
        }
129 6
        return (s);
130
}