blob: e39e40941c48c4b2f3c70d5dfaf18c646d344d94 [file] [log] [blame]
Lucas De Marchie8847fd2011-11-30 15:23:28 -02001/* index.c: module index file shared functions for modprobe and depmod
2 Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>.
3
4 These programs are free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with these programs. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <arpa/inet.h> /* htonl */
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <errno.h>
23#include <fnmatch.h>
24
25#include "libkmod-private.h"
26#include "libkmod-index.h"
27#include "macro.h"
28
Lucas De Marchie8847fd2011-11-30 15:23:28 -020029void index_values_free(struct index_value *values)
30{
31 while (values) {
32 struct index_value *value = values;
33
34 values = value->next;
35 free(value);
36 }
37}
38
Lucas De Marchie8847fd2011-11-30 15:23:28 -020039static int add_value(struct index_value **values,
40 const char *value, unsigned int priority)
41{
42 struct index_value *v;
43 int duplicate = 0;
44 int len;
45
46 /* report the presence of duplicate values */
47 for (v = *values; v; v = v->next) {
48 if (streq(v->value, value))
49 duplicate = 1;
50 }
51
52 /* find position to insert value */
53 while (*values && (*values)->priority < priority)
54 values = &(*values)->next;
55
56 len = strlen(value);
57 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
58 v->next = *values;
59 v->priority = priority;
60 memcpy(v->value, value, len + 1);
61 *values = v;
62
63 return duplicate;
64}
65
Lucas De Marchi93688882011-12-02 10:05:31 -020066static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020067{
68 fatal("Module index: unexpected error: %s\n"
69 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
70}
71
72static int read_char(FILE *in)
73{
74 int ch;
75
76 errno = 0;
77 ch = getc_unlocked(in);
78 if (ch == EOF)
79 read_error();
80 return ch;
81}
82
83static uint32_t read_long(FILE *in)
84{
85 uint32_t l;
86
87 errno = 0;
88 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
89 read_error();
90 return ntohl(l);
91}
92
93/*
94 * Buffer abstract data type
95 *
96 * Used internally to store the current path during tree traversal.
97 * They help build wildcard key strings to pass to fnmatch(),
98 * as well as building values of matching keys.
99 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200100struct buffer {
101 char *bytes;
102 unsigned size;
103 unsigned used;
104};
105
106static void buf__realloc(struct buffer *buf, unsigned size)
107{
108 if (size > buf->size) {
109 buf->bytes = NOFAIL(realloc(buf->bytes, size));
110 buf->size = size;
111 }
112}
113
Lucas De Marchi93688882011-12-02 10:05:31 -0200114static struct buffer *buf_create(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200115{
116 struct buffer *buf;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200117
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200118 buf = NOFAIL(calloc(sizeof(struct buffer), 1));
119 buf__realloc(buf, 256);
120 return buf;
121}
122
123static void buf_destroy(struct buffer *buf)
124{
125 free(buf->bytes);
126 free(buf);
127}
128
129/* Destroy buffer and return a copy as a C string */
130static char *buf_detach(struct buffer *buf)
131{
132 char *bytes;
133
134 bytes = NOFAIL(realloc(buf->bytes, buf->used + 1));
135 bytes[buf->used] = '\0';
136
137 free(buf);
138 return bytes;
139}
140
141/* Return a C string owned by the buffer
142 (invalidated if the buffer is changed).
143 */
144static const char *buf_str(struct buffer *buf)
145{
146 buf__realloc(buf, buf->used + 1);
147 buf->bytes[buf->used] = '\0';
148 return buf->bytes;
149}
150
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200151static void buf_pushchar(struct buffer *buf, char ch)
152{
153 buf__realloc(buf, buf->used + 1);
154 buf->bytes[buf->used] = ch;
155 buf->used++;
156}
157
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200158static unsigned buf_freadchars(struct buffer *buf, FILE *in)
159{
160 unsigned i = 0;
161 int ch;
162
163 while ((ch = read_char(in))) {
164 buf_pushchar(buf, ch);
165 i++;
166 }
167
168 return i;
169}
170
171static void buf_popchar(struct buffer *buf)
172{
173 buf->used--;
174}
175
176static void buf_popchars(struct buffer *buf, unsigned n)
177{
178 buf->used -= n;
179}
180
181static void buf_clear(struct buffer *buf)
182{
183 buf->used = 0;
184}
185
186/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200187 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200188 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200189struct index_node_f {
190 FILE *file;
191 char *prefix; /* path compression */
192 struct index_value *values;
193 unsigned char first; /* range of child nodes */
194 unsigned char last;
195 uint32_t children[0];
196};
197
198static struct index_node_f *index_read(FILE *in, uint32_t offset)
199{
200 struct index_node_f *node;
201 char *prefix;
202 int i, child_count = 0;
203
204 if ((offset & INDEX_NODE_MASK) == 0)
205 return NULL;
206
207 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200208
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200209 if (offset & INDEX_NODE_PREFIX) {
210 struct buffer *buf = buf_create();
211 buf_freadchars(buf, in);
212 prefix = buf_detach(buf);
213 } else
214 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200215
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200216 if (offset & INDEX_NODE_CHILDS) {
217 char first = read_char(in);
218 char last = read_char(in);
219 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200220
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200221 node = NOFAIL(malloc(sizeof(struct index_node_f) +
222 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200223
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200224 node->first = first;
225 node->last = last;
226
227 for (i = 0; i < child_count; i++)
228 node->children[i] = read_long(in);
229 } else {
230 node = NOFAIL(malloc(sizeof(struct index_node_f)));
231 node->first = INDEX_CHILDMAX;
232 node->last = 0;
233 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200234
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200235 node->values = NULL;
236 if (offset & INDEX_NODE_VALUES) {
237 int value_count;
238 struct buffer *buf = buf_create();
239 const char *value;
240 unsigned int priority;
241
242 value_count = read_long(in);
243
244 while (value_count--) {
245 priority = read_long(in);
246 buf_freadchars(buf, in);
247 value = buf_str(buf);
248 add_value(&node->values, value, priority);
249 buf_clear(buf);
250 }
251 buf_destroy(buf);
252 }
253
254 node->prefix = prefix;
255 node->file = in;
256 return node;
257}
258
259static void index_close(struct index_node_f *node)
260{
261 free(node->prefix);
262 index_values_free(node->values);
263 free(node);
264}
265
266struct index_file {
267 FILE *file;
268 uint32_t root_offset;
269};
270
271/* Failures are silent; modprobe will fall back to text files */
272struct index_file *index_file_open(const char *filename)
273{
274 FILE *file;
275 uint32_t magic, version;
276 struct index_file *new;
277
278 file = fopen(filename, "r");
279 if (!file)
280 return NULL;
281 errno = EINVAL;
282
283 magic = read_long(file);
284 if (magic != INDEX_MAGIC)
285 return NULL;
286
287 version = read_long(file);
288 if (version >> 16 != INDEX_VERSION_MAJOR)
289 return NULL;
290
291 new = NOFAIL(malloc(sizeof(struct index_file)));
292 new->file = file;
293 new->root_offset = read_long(new->file);
294
295 errno = 0;
296 return new;
297}
298
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200299void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200300{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200301 fclose(idx->file);
302 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200303}
304
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200305static struct index_node_f *index_readroot(struct index_file *in)
306{
307 return index_read(in->file, in->root_offset);
308}
309
310static struct index_node_f *index_readchild(const struct index_node_f *parent,
311 int ch)
312{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200313 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200314 return index_read(parent->file,
315 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200316 }
317
318 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200319}
320
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200321static char *index_search__node(struct index_node_f *node, const char *key, int i)
322{
323 char *value;
324 struct index_node_f *child;
325 int ch;
326 int j;
327
328 while(node) {
329 for (j = 0; node->prefix[j]; j++) {
330 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200331
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200332 if (ch != key[i+j]) {
333 index_close(node);
334 return NULL;
335 }
336 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200337
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200338 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200339
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200340 if (key[i] == '\0') {
341 if (node->values) {
342 value = strdup(node->values[0].value);
343 index_close(node);
344 return value;
345 } else {
346 return NULL;
347 }
348 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200349
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200350 child = index_readchild(node, key[i]);
351 index_close(node);
352 node = child;
353 i++;
354 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200355
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200356 return NULL;
357}
358
359/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200360 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200361 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200362 * Returns the value of the first match
363 *
364 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200365 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200366char *index_search(struct index_file *in, const char *key)
367{
368 struct index_node_f *root;
369 char *value;
370
371 root = index_readroot(in);
372 value = index_search__node(root, key, 0);
373
374 return value;
375}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200376
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200377
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200378
379/* Level 4: add all the values from a matching node */
380static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200381 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200382{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200383 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200384
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200385 for (v = node->values; v != NULL; v = v->next)
386 add_value(out, v->value, v->priority);
387
388 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200389}
390
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200391/*
392 * Level 3: traverse a sub-keyspace which starts with a wildcard,
393 * looking for matches.
394 */
395static void index_searchwild__all(struct index_node_f *node, int j,
396 struct buffer *buf,
397 const char *subkey,
398 struct index_value **out)
399{
400 int pushed = 0;
401 int ch;
402
403 while (node->prefix[j]) {
404 ch = node->prefix[j];
405
406 buf_pushchar(buf, ch);
407 pushed++;
408 j++;
409 }
410
411 for (ch = node->first; ch <= node->last; ch++) {
412 struct index_node_f *child = index_readchild(node, ch);
413
414 if (!child)
415 continue;
416
417 buf_pushchar(buf, ch);
418 index_searchwild__all(child, 0, buf, subkey, out);
419 buf_popchar(buf);
420 }
421
422 if (node->values) {
423 if (fnmatch(buf_str(buf), subkey, 0) == 0)
424 index_searchwild__allvalues(node, out);
425 } else {
426 index_close(node);
427 }
428
429 buf_popchars(buf, pushed);
430}
431
432/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200433static void index_searchwild__node(struct index_node_f *node,
434 struct buffer *buf,
435 const char *key, int i,
436 struct index_value **out)
437{
438 struct index_node_f *child;
439 int j;
440 int ch;
441
442 while(node) {
443 for (j = 0; node->prefix[j]; j++) {
444 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200445
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200446 if (ch == '*' || ch == '?' || ch == '[') {
447 index_searchwild__all(node, j, buf,
448 &key[i+j], out);
449 return;
450 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200451
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200452 if (ch != key[i+j]) {
453 index_close(node);
454 return;
455 }
456 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200457
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200458 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200459
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200460 child = index_readchild(node, '*');
461 if (child) {
462 buf_pushchar(buf, '*');
463 index_searchwild__all(child, 0, buf, &key[i], out);
464 buf_popchar(buf);
465 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200466
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200467 child = index_readchild(node, '?');
468 if (child) {
469 buf_pushchar(buf, '?');
470 index_searchwild__all(child, 0, buf, &key[i], out);
471 buf_popchar(buf);
472 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200473
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200474 child = index_readchild(node, '[');
475 if (child) {
476 buf_pushchar(buf, '[');
477 index_searchwild__all(child, 0, buf, &key[i], out);
478 buf_popchar(buf);
479 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200480
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200481 if (key[i] == '\0') {
482 index_searchwild__allvalues(node, out);
483
484 return;
485 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200486
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200487 child = index_readchild(node, key[i]);
488 index_close(node);
489 node = child;
490 i++;
491 }
492}
493
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200494/*
495 * Search the index for a key. The index may contain wildcards.
496 *
497 * Returns a list of all the values of matching keys.
498 */
499struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200500{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200501 struct index_node_f *root = index_readroot(in);
502 struct buffer *buf = buf_create();
503 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200504
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200505 index_searchwild__node(root, buf, key, 0, &out);
506 buf_destroy(buf);
507 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200508}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200509
510#include <sys/mman.h>
511#include <sys/stat.h>
512#include <unistd.h>
513
514/**************************************************************************/
515/*
516 * Alternative implementation, using mmap to map all the file to memory when
517 * starting
518 */
519struct index_mm {
520 struct kmod_ctx *ctx;
521 void *mm;
522 uint32_t root_offset;
523 size_t size;
524};
525
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200526struct index_mm_node {
527 struct index_mm *idx;
528 char *prefix;
529 struct index_value *values;
530 unsigned char first;
531 unsigned char last;
532 uint32_t children[];
533};
534
535static inline uint32_t read_long_mm(void **p)
536{
537 uint32_t v = **((uint32_t **)p);
538
539 *p = *((uint8_t **)p) + sizeof(uint32_t);
540
541 return ntohl(v);
542}
543
544static inline uint8_t read_char_mm(void **p)
545{
546 uint8_t *v = *((uint8_t **)p);
547 *p = v + 1;
548 return *v;
549}
550
551static inline char *read_alloc_chars_mm(void **p)
552{
553 char *s = *((char **)p);
554 size_t len = strlen(s) + 1;
555 *p = ((char *)p) + len;
556
557 return memdup(s, len);
558}
559
560static inline char *read_chars_mm(void **p)
561{
562 char *s = *((char **)p);
563 size_t len = strlen(s) + 1;
564 *p = ((char *)p) + len;
565
566 return s;
567}
568
569static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
570 uint32_t offset) {
571 void *p = idx->mm;
572 struct index_mm_node *node;
573 char *prefix;
574 int i, child_count = 0;
575
576
577 if ((offset & INDEX_NODE_MASK) == 0)
578 return NULL;
579
580 p = (char *)p + (offset & INDEX_NODE_MASK);
581
582 if (offset & INDEX_NODE_PREFIX)
583 prefix = read_alloc_chars_mm(&p);
584 else
585 prefix = strdup("");
586
587 if (offset & INDEX_NODE_CHILDS) {
588 char first = read_char_mm(&p);
589 char last = read_char_mm(&p);
590 child_count = last - first + 1;
591
592 node = malloc(sizeof(*node) + sizeof(uint32_t) * child_count);
593
594 node->first = first;
595 node->last = last;
596
597 for (i = 0; i < child_count; i++)
598 node->children[i] = read_long_mm(&p);
599 } else {
600 node = malloc(sizeof(*node));
601 node->first = INDEX_CHILDMAX;
602 node->last = 0;
603 }
604
605 node->values = NULL;
606
607 if (offset & INDEX_NODE_VALUES) {
608 uint32_t j;
609
610 for (j = read_long_mm(&p); j > 0; j--) {
611 unsigned int priority;
612 const char *value;
613
614 priority = read_long_mm(&p);
615 value = read_chars_mm(&p);
616 add_value(&node->values, value, priority);
617 }
618 }
619
620 node->prefix = prefix;
621 node->idx = idx;
622
623 return node;
624}
625
626static void index_mm_free_node(struct index_mm_node *node)
627{
628 free(node->prefix);
629 index_values_free(node->values);
630 free(node);
631}
632
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200633struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
634{
635 int fd;
636 struct stat st;
637 struct index_mm *idx;
638 struct {
639 uint32_t magic;
640 uint32_t version;
641 uint32_t root_offset;
642 } hdr;
643 void *p;
644
645 DBG(ctx, "file=%s\n", filename);
646
647 if ((fd = open(filename, O_RDONLY)) < 0) {
648 ERR(ctx, "%m\n");
649 return NULL;
650 }
651
652 fstat(fd, &st);
653
654 idx = malloc(sizeof(*idx));
655 if (idx == NULL) {
656 ERR(ctx, "%m\n");
657 goto fail;
658 }
659
660 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
661 MAP_PRIVATE | MAP_POPULATE,
662 fd, 0)) == MAP_FAILED) {
663 ERR(ctx, "%m\n");
664 goto fail;
665 }
666
667 p = idx->mm;
668 hdr.magic = read_long_mm(&p);
669 hdr.version = read_long_mm(&p);
670 hdr.root_offset = read_long_mm(&p);
671
672 if (hdr.magic != INDEX_MAGIC) {
673 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
674 INDEX_MAGIC);
675 goto fail;
676 }
677
678 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
679 ERR(ctx, "major version check fail: %u instead of %u\n",
680 hdr.version, INDEX_MAGIC);
681 goto fail;
682 }
683
684 idx->root_offset = hdr.root_offset;
685 idx->size = st.st_size;
686 idx->ctx = ctx;
687 close(fd);
688
689 return idx;
690
691fail:
692 close(fd);
693 if (idx->mm)
694 munmap(idx->mm, st.st_size);
695 free(idx);
696 return NULL;
697}
698
699void index_mm_close(struct index_mm *idx)
700{
701 munmap(idx->mm, idx->size);
702 free(idx);
703}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200704
705static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
706{
707 return index_mm_read_node(idx, idx->root_offset);
708}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200709
710static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
711 int ch)
712{
713 if (parent->first <= ch && ch <= parent->last) {
714 return index_mm_read_node(parent->idx,
715 parent->children[ch - parent->first]);
716 }
717
718 return NULL;
719}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200720
721static char *index_mm_search_node(struct index_mm_node *node, const char *key,
722 int i)
723{
724 char *value;
725 struct index_mm_node *child;
726 int ch;
727 int j;
728
729 while(node) {
730 for (j = 0; node->prefix[j]; j++) {
731 ch = node->prefix[j];
732
733 if (ch != key[i+j]) {
734 index_mm_free_node(node);
735 return NULL;
736 }
737 }
738
739 i += j;
740
741 if (key[i] == '\0') {
742 if (node->values) {
743 value = strdup(node->values[0].value);
744 index_mm_free_node(node);
745 return value;
746 } else {
747 return NULL;
748 }
749 }
750
751 child = index_mm_readchild(node, key[i]);
752 index_mm_free_node(node);
753 node = child;
754 i++;
755 }
756
757 return NULL;
758}
Lucas De Marchib797b792011-12-02 17:49:03 -0200759
760/*
761 * Search the index for a key
762 *
763 * Returns the value of the first match
764 *
765 * The recursive functions free their node argument (using index_close).
766 */
767char *index_mm_search(struct index_mm *idx, const char *key)
768{
769 struct index_mm_node *root;
770 char *value;
771
772 root = index_mm_readroot(idx);
773 value = index_mm_search_node(root, key, 0);
774
775 return value;
776}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200777
778/* Level 4: add all the values from a matching node */
779static void index_mm_searchwild_allvalues(struct index_mm_node *node,
780 struct index_value **out)
781{
782 struct index_value *v;
783
784 for (v = node->values; v != NULL; v = v->next)
785 add_value(out, v->value, v->priority);
786
787 index_mm_free_node(node);
788}
789
790/*
791 * Level 3: traverse a sub-keyspace which starts with a wildcard,
792 * looking for matches.
793 */
794static void index_mm_searchwild_all(struct index_mm_node *node, int j,
795 struct buffer *buf,
796 const char *subkey,
797 struct index_value **out)
798{
799 int pushed = 0;
800 int ch;
801
802 while (node->prefix[j]) {
803 ch = node->prefix[j];
804
805 buf_pushchar(buf, ch);
806 pushed++;
807 j++;
808 }
809
810 for (ch = node->first; ch <= node->last; ch++) {
811 struct index_mm_node *child = index_mm_readchild(node, ch);
812
813 if (!child)
814 continue;
815
816 buf_pushchar(buf, ch);
817 index_mm_searchwild_all(child, 0, buf, subkey, out);
818 buf_popchar(buf);
819 }
820
821 if (node->values) {
822 if (fnmatch(buf_str(buf), subkey, 0) == 0)
823 index_mm_searchwild_allvalues(node, out);
824 } else {
825 index_mm_free_node(node);
826 }
827
828 buf_popchars(buf, pushed);
829}
830
831/* Level 2: descend the tree (until we hit a wildcard) */
832static void index_mm_searchwild_node(struct index_mm_node *node,
833 struct buffer *buf,
834 const char *key, int i,
835 struct index_value **out)
836{
837 struct index_mm_node *child;
838 int j;
839 int ch;
840
841 while(node) {
842 for (j = 0; node->prefix[j]; j++) {
843 ch = node->prefix[j];
844
845 if (ch == '*' || ch == '?' || ch == '[') {
846 index_mm_searchwild_all(node, j, buf,
847 &key[i+j], out);
848 return;
849 }
850
851 if (ch != key[i+j]) {
852 index_mm_free_node(node);
853 return;
854 }
855 }
856
857 i += j;
858
859 child = index_mm_readchild(node, '*');
860 if (child) {
861 buf_pushchar(buf, '*');
862 index_mm_searchwild_all(child, 0, buf, &key[i], out);
863 buf_popchar(buf);
864 }
865
866 child = index_mm_readchild(node, '?');
867 if (child) {
868 buf_pushchar(buf, '?');
869 index_mm_searchwild_all(child, 0, buf, &key[i], out);
870 buf_popchar(buf);
871 }
872
873 child = index_mm_readchild(node, '[');
874 if (child) {
875 buf_pushchar(buf, '[');
876 index_mm_searchwild_all(child, 0, buf, &key[i], out);
877 buf_popchar(buf);
878 }
879
880 if (key[i] == '\0') {
881 index_mm_searchwild_allvalues(node, out);
882
883 return;
884 }
885
886 child = index_mm_readchild(node, key[i]);
887 index_mm_free_node(node);
888 node = child;
889 i++;
890 }
891}
892
893/*
894 * Search the index for a key. The index may contain wildcards.
895 *
896 * Returns a list of all the values of matching keys.
897 */
898struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
899{
900 struct index_mm_node *root = index_mm_readroot(idx);
901 struct buffer *buf = buf_create();
902 struct index_value *out = NULL;
903
904 index_mm_searchwild_node(root, buf, key, 0, &out);
905 buf_destroy(buf);
906 return out;
907}