~ubuntu-branches/ubuntu/saucy/postfix/saucy

« back to all changes in this revision

Viewing changes to src/util/dict_thash.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2011-02-22 11:20:43 UTC
  • mfrom: (1.1.27 upstream)
  • Revision ID: james.westby@ubuntu.com-20110222112043-c34ht219w3ybrilr
Tags: 2.8.0-2
* a little more lintian cleanup
* Fix missing format strings in smtp-sink.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      dict_thash 3
 
4
/* SUMMARY
 
5
/*      dictionary manager interface to hashed flat text files
 
6
/* SYNOPSIS
 
7
/*      #include <dict_thash.h>
 
8
/*
 
9
/*      DICT    *dict_thash_open(path, open_flags, dict_flags)
 
10
/*      const char *name;
 
11
/*      const char *path;
 
12
/*      int     open_flags;
 
13
/*      int     dict_flags;
 
14
/* DESCRIPTION
 
15
/*      dict_thash_open() opens the named flat text file, creates
 
16
/*      an in-memory hash table, and makes it available via the
 
17
/*      generic interface described in dict_open(3). The input
 
18
/*      format is as with postmap(1).
 
19
/* DIAGNOSTICS
 
20
/*      Fatal errors: cannot open file, out of memory.
 
21
/* SEE ALSO
 
22
/*      dict(3) generic dictionary manager
 
23
/* LICENSE
 
24
/* .ad
 
25
/* .fi
 
26
/*      The Secure Mailer license must be distributed with this software.
 
27
/* AUTHOR(S)
 
28
/*      Wietse Venema
 
29
/*      IBM T.J. Watson Research
 
30
/*      P.O. Box 704
 
31
/*      Yorktown Heights, NY 10598, USA
 
32
/*--*/
 
33
 
 
34
/* System library. */
 
35
 
 
36
#include <sys_defs.h>
 
37
#include <sys/stat.h>
 
38
#include <ctype.h>
 
39
#include <string.h>
 
40
 
 
41
/* Utility library. */
 
42
 
 
43
#include <msg.h>
 
44
#include <mymalloc.h>
 
45
#include <htable.h>
 
46
#include <iostuff.h>
 
47
#include <vstring.h>
 
48
#include <stringops.h>
 
49
#include <readlline.h>
 
50
#include <dict.h>
 
51
#include <dict_thash.h>
 
52
 
 
53
/* Application-specific. */
 
54
 
 
55
typedef struct {
 
56
    DICT    dict;                       /* generic members */
 
57
    HTABLE *table;                      /* in-memory hash */
 
58
    HTABLE_INFO **info;                 /* for iterator */
 
59
    HTABLE_INFO **cursor;               /* ditto */
 
60
}       DICT_THASH;
 
61
 
 
62
#define STR     vstring_str
 
63
 
 
64
/* dict_thash_lookup - find database entry */
 
65
 
 
66
static const char *dict_thash_lookup(DICT *dict, const char *name)
 
67
{
 
68
    DICT_THASH *dict_thash = (DICT_THASH *) dict;
 
69
    const char *result = 0;
 
70
 
 
71
    dict_errno = 0;
 
72
 
 
73
    /*
 
74
     * Optionally fold the key.
 
75
     */
 
76
    if (dict->flags & DICT_FLAG_FOLD_FIX) {
 
77
        if (dict->fold_buf == 0)
 
78
            dict->fold_buf = vstring_alloc(10);
 
79
        vstring_strcpy(dict->fold_buf, name);
 
80
        name = lowercase(vstring_str(dict->fold_buf));
 
81
    }
 
82
 
 
83
    /*
 
84
     * Look up the value.
 
85
     */
 
86
    result = htable_find(dict_thash->table, name);
 
87
 
 
88
    return (result);
 
89
}
 
90
 
 
91
/* dict_thash_sequence - traverse the dictionary */
 
92
 
 
93
static int dict_thash_sequence(DICT *dict, int function,
 
94
                                       const char **key, const char **value)
 
95
{
 
96
    const char *myname = "dict_thash_sequence";
 
97
    DICT_THASH *dict_thash = (DICT_THASH *) dict;
 
98
 
 
99
    /*
 
100
     * Determine and execute the seek function.
 
101
     */
 
102
    switch (function) {
 
103
    case DICT_SEQ_FUN_FIRST:
 
104
        if (dict_thash->info == 0)
 
105
            dict_thash->info = htable_list(dict_thash->table);
 
106
        dict_thash->cursor = dict_thash->info;
 
107
        break;
 
108
    case DICT_SEQ_FUN_NEXT:
 
109
        if (dict_thash->cursor[0])
 
110
            dict_thash->cursor += 1;
 
111
        break;
 
112
    default:
 
113
        msg_panic("%s: invalid function: %d", myname, function);
 
114
    }
 
115
 
 
116
    /*
 
117
     * Return the entry under the cursor.
 
118
     */
 
119
    if (dict_thash->cursor[0]) {
 
120
        *key = dict_thash->cursor[0]->key;
 
121
        *value = dict_thash->cursor[0]->value;
 
122
        return (0);
 
123
    } else {
 
124
        return (1);
 
125
    }
 
126
}
 
127
 
 
128
/* dict_thash_close - disassociate from data base */
 
129
 
 
130
static void dict_thash_close(DICT *dict)
 
131
{
 
132
    DICT_THASH *dict_thash = (DICT_THASH *) dict;
 
133
 
 
134
    htable_free(dict_thash->table, myfree);
 
135
    if (dict_thash->info)
 
136
        myfree((char *) dict_thash->info);
 
137
    if (dict->fold_buf)
 
138
        vstring_free(dict->fold_buf);
 
139
    dict_free(dict);
 
140
}
 
141
 
 
142
/* dict_thash_open - open flat text data base */
 
143
 
 
144
DICT   *dict_thash_open(const char *path, int open_flags, int dict_flags)
 
145
{
 
146
    DICT_THASH *dict_thash;
 
147
    VSTREAM *fp;
 
148
    struct stat st;
 
149
    time_t  before;
 
150
    time_t  after;
 
151
    VSTRING *line_buffer = vstring_alloc(100);
 
152
    int     lineno;
 
153
    char   *key;
 
154
    char   *value;
 
155
    HTABLE_INFO *ht;
 
156
 
 
157
    /*
 
158
     * Sanity checks.
 
159
     */
 
160
    if (open_flags != O_RDONLY)
 
161
        msg_fatal("%s:%s map requires O_RDONLY access mode",
 
162
                  DICT_TYPE_THASH, path);
 
163
 
 
164
    /*
 
165
     * Create the in-memory table.
 
166
     */
 
167
    dict_thash = (DICT_THASH *)
 
168
        dict_alloc(DICT_TYPE_THASH, path, sizeof(*dict_thash));
 
169
    dict_thash->dict.lookup = dict_thash_lookup;
 
170
    dict_thash->dict.sequence = dict_thash_sequence;
 
171
    dict_thash->dict.close = dict_thash_close;
 
172
    dict_thash->dict.flags = dict_flags | DICT_FLAG_DUP_WARN | DICT_FLAG_FIXED;
 
173
    if (dict_flags & DICT_FLAG_FOLD_FIX)
 
174
        dict_thash->dict.fold_buf = vstring_alloc(10);
 
175
    dict_thash->info = 0;
 
176
 
 
177
    /*
 
178
     * Read the flat text file into in-memory hash. Read the file again if it
 
179
     * may have changed while we were reading.
 
180
     */
 
181
    for (before = time((time_t *) 0); /* see below */ ; before = after) {
 
182
        if ((fp = vstream_fopen(path, open_flags, 0644)) == 0)
 
183
            msg_fatal("open database %s: %m", path);
 
184
        lineno = 0;
 
185
        dict_thash->table = htable_create(13);
 
186
        while (readlline(line_buffer, fp, &lineno)) {
 
187
 
 
188
            /*
 
189
             * Split on the first whitespace character, then trim leading and
 
190
             * trailing whitespace from key and value.
 
191
             */
 
192
            key = STR(line_buffer);
 
193
            value = key + strcspn(key, " \t\r\n");
 
194
            if (*value)
 
195
                *value++ = 0;
 
196
            while (ISSPACE(*value))
 
197
                value++;
 
198
            trimblanks(key, 0)[0] = 0;
 
199
            trimblanks(value, 0)[0] = 0;
 
200
 
 
201
            /*
 
202
             * Enforce the "key whitespace value" format. Disallow missing
 
203
             * keys or missing values.
 
204
             */
 
205
            if (*key == 0 || *value == 0) {
 
206
                msg_warn("%s, line %d: expected format: key whitespace value"
 
207
                         " -- ignoring this line", path, lineno);
 
208
                continue;
 
209
            }
 
210
            if (key[strlen(key) - 1] == ':')
 
211
                msg_warn("%s, line %d: record is in \"key: value\" format;"
 
212
                         " is this an alias file?", path, lineno);
 
213
 
 
214
            /*
 
215
             * Optionally fold the key.
 
216
             */
 
217
            if (dict_thash->dict.flags & DICT_FLAG_FOLD_FIX)
 
218
                lowercase(key);
 
219
 
 
220
            /*
 
221
             * Store the value under the key. Handle duplicates
 
222
             * appropriately.
 
223
             */
 
224
            if ((ht = htable_locate(dict_thash->table, key)) != 0) {
 
225
                if (dict_thash->dict.flags & DICT_FLAG_DUP_IGNORE) {
 
226
                     /* void */ ;
 
227
                } else if (dict_thash->dict.flags & DICT_FLAG_DUP_REPLACE) {
 
228
                    myfree(ht->value);
 
229
                    ht->value = mystrdup(value);
 
230
                } else if (dict_thash->dict.flags & DICT_FLAG_DUP_WARN) {
 
231
                    msg_warn("%s, line %d: duplicate entry: \"%s\"",
 
232
                             path, lineno, key);
 
233
                } else {
 
234
                    msg_fatal("%s, line %d: duplicate entry: \"%s\"",
 
235
                              path, lineno, key);
 
236
                }
 
237
            } else {
 
238
                htable_enter(dict_thash->table, key, mystrdup(value));
 
239
            }
 
240
        }
 
241
 
 
242
        /*
 
243
         * See if the source file is hot.
 
244
         */
 
245
        if (fstat(vstream_fileno(fp), &st) < 0)
 
246
            msg_fatal("fstat %s: %m", path);
 
247
        if (vstream_fclose(fp))
 
248
            msg_fatal("read %s: %m", path);
 
249
        after = time((time_t *) 0);
 
250
        if (st.st_mtime < before - 1 || st.st_mtime > after)
 
251
            break;
 
252
 
 
253
        /*
 
254
         * Yes, it is hot. Discard the result and read the file again.
 
255
         */
 
256
        htable_free(dict_thash->table, myfree);
 
257
        if (msg_verbose > 1)
 
258
            msg_info("pausing to let file %s cool down", path);
 
259
        doze(300000);
 
260
    }
 
261
    vstring_free(line_buffer);
 
262
 
 
263
    return (DICT_DEBUG (&dict_thash->dict));
 
264
}