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 8
free_frfile(void *ptr)
65
{
66
        struct frfile *frf;
67
68 8
        CAST_OBJ_NOTNULL(frf, ptr, CACHED_FILE_MAGIC);
69
70 8
        AZ(pthread_mutex_lock(&frmtx));
71 8
        if (--frf->refcount > 0)
72 8
                frf = NULL;
73
        else
74 0
                VTAILQ_REMOVE(&frlist, frf, list);
75 8
        AZ(pthread_mutex_unlock(&frmtx));
76 8
        if (frf != NULL) {
77 0
                free(frf->contents);
78 0
                free(frf->file_name);
79 0
                FREE_OBJ(frf);
80
        }
81 8
}
82
83
VCL_STRING v_matchproto_(td_std_fileread)
84 44
vmod_fileread(VRT_CTX, struct vmod_priv *priv,
85
    VCL_STRING file_name)
86
{
87 44
        struct frfile *frf = NULL;
88
        char *s;
89
90 44
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
91 44
        AN(priv);
92
93 44
        if (file_name == NULL)
94 0
                return (NULL);
95
96 44
        if (priv->priv != NULL) {
97 24
                CAST_OBJ_NOTNULL(frf, priv->priv, CACHED_FILE_MAGIC);
98 24
                if (!strcmp(file_name, frf->file_name))
99 8
                        return (frf->contents);
100
        }
101
102 36
        AZ(pthread_mutex_lock(&frmtx));
103 36
        if (frf != NULL)
104 16
                frf->refcount--;
105 78
        VTAILQ_FOREACH(frf, &frlist, list) {
106 64
                if (!strcmp(file_name, frf->file_name)) {
107 22
                        frf->refcount++;
108 22
                        break;
109
                }
110
        }
111 36
        AZ(pthread_mutex_unlock(&frmtx));
112 36
        if (frf != NULL) {
113 22
                priv->free = free_frfile;
114 22
                priv->priv = frf;
115 22
                return (frf->contents);
116
        }
117
118 14
        s = VFIL_readfile(NULL, file_name, NULL);
119 14
        if (s != NULL) {
120 14
                ALLOC_OBJ(frf, CACHED_FILE_MAGIC);
121 14
                AN(frf);
122 14
                frf->file_name = strdup(file_name);
123 14
                AN(frf->file_name);
124 14
                frf->refcount = 1;
125 14
                frf->contents = s;
126 14
                priv->free = free_frfile;
127 14
                priv->priv = frf;
128 14
                AZ(pthread_mutex_lock(&frmtx));
129 14
                VTAILQ_INSERT_HEAD(&frlist, frf, list);
130 14
                AZ(pthread_mutex_unlock(&frmtx));
131
        }
132 14
        return (s);
133
}