blob: 37e30c91f10551027fca508901e77496481ac96e [file] [log] [blame]
Lucas De Marchi8f923be2011-12-03 04:28:49 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
5 * Copyright (C) 2011 ProFUSION embedded systems
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation version 2.1.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -020020
21#include <arpa/inet.h> /* htonl */
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <errno.h>
26#include <fnmatch.h>
27
28#include "libkmod-private.h"
29#include "libkmod-index.h"
30#include "macro.h"
31
Lucas De Marchi8f923be2011-12-03 04:28:49 -020032/* index.c: module index file shared functions for modprobe and depmod */
33
Lucas De Marchie8847fd2011-11-30 15:23:28 -020034void index_values_free(struct index_value *values)
35{
36 while (values) {
37 struct index_value *value = values;
38
39 values = value->next;
40 free(value);
41 }
42}
43
Lucas De Marchie8847fd2011-11-30 15:23:28 -020044static int add_value(struct index_value **values,
45 const char *value, unsigned int priority)
46{
47 struct index_value *v;
48 int duplicate = 0;
49 int len;
50
51 /* report the presence of duplicate values */
52 for (v = *values; v; v = v->next) {
53 if (streq(v->value, value))
54 duplicate = 1;
55 }
56
57 /* find position to insert value */
58 while (*values && (*values)->priority < priority)
59 values = &(*values)->next;
60
61 len = strlen(value);
62 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
63 v->next = *values;
64 v->priority = priority;
65 memcpy(v->value, value, len + 1);
66 *values = v;
67
68 return duplicate;
69}
70
Lucas De Marchi93688882011-12-02 10:05:31 -020071static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020072{
73 fatal("Module index: unexpected error: %s\n"
74 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
75}
76
77static int read_char(FILE *in)
78{
79 int ch;
80
81 errno = 0;
82 ch = getc_unlocked(in);
83 if (ch == EOF)
84 read_error();
85 return ch;
86}
87
88static uint32_t read_long(FILE *in)
89{
90 uint32_t l;
91
92 errno = 0;
93 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
94 read_error();
95 return ntohl(l);
96}
97
98/*
99 * Buffer abstract data type
100 *
101 * Used internally to store the current path during tree traversal.
102 * They help build wildcard key strings to pass to fnmatch(),
103 * as well as building values of matching keys.
104 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200105struct buffer {
106 char *bytes;
107 unsigned size;
108 unsigned used;
109};
110
111static void buf__realloc(struct buffer *buf, unsigned size)
112{
113 if (size > buf->size) {
114 buf->bytes = NOFAIL(realloc(buf->bytes, size));
115 buf->size = size;
116 }
117}
118
Lucas De Marchi93688882011-12-02 10:05:31 -0200119static struct buffer *buf_create(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200120{
121 struct buffer *buf;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200122
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200123 buf = NOFAIL(calloc(sizeof(struct buffer), 1));
124 buf__realloc(buf, 256);
125 return buf;
126}
127
128static void buf_destroy(struct buffer *buf)
129{
130 free(buf->bytes);
131 free(buf);
132}
133
134/* Destroy buffer and return a copy as a C string */
135static char *buf_detach(struct buffer *buf)
136{
137 char *bytes;
138
139 bytes = NOFAIL(realloc(buf->bytes, buf->used + 1));
140 bytes[buf->used] = '\0';
141
142 free(buf);
143 return bytes;
144}
145
146/* Return a C string owned by the buffer
147 (invalidated if the buffer is changed).
148 */
149static const char *buf_str(struct buffer *buf)
150{
151 buf__realloc(buf, buf->used + 1);
152 buf->bytes[buf->used] = '\0';
153 return buf->bytes;
154}
155
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200156static void buf_pushchar(struct buffer *buf, char ch)
157{
158 buf__realloc(buf, buf->used + 1);
159 buf->bytes[buf->used] = ch;
160 buf->used++;
161}
162
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200163static unsigned buf_freadchars(struct buffer *buf, FILE *in)
164{
165 unsigned i = 0;
166 int ch;
167
168 while ((ch = read_char(in))) {
169 buf_pushchar(buf, ch);
170 i++;
171 }
172
173 return i;
174}
175
176static void buf_popchar(struct buffer *buf)
177{
178 buf->used--;
179}
180
181static void buf_popchars(struct buffer *buf, unsigned n)
182{
183 buf->used -= n;
184}
185
186static void buf_clear(struct buffer *buf)
187{
188 buf->used = 0;
189}
190
191/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200192 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200193 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200194struct index_node_f {
195 FILE *file;
196 char *prefix; /* path compression */
197 struct index_value *values;
198 unsigned char first; /* range of child nodes */
199 unsigned char last;
200 uint32_t children[0];
201};
202
203static struct index_node_f *index_read(FILE *in, uint32_t offset)
204{
205 struct index_node_f *node;
206 char *prefix;
207 int i, child_count = 0;
208
209 if ((offset & INDEX_NODE_MASK) == 0)
210 return NULL;
211
212 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200213
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200214 if (offset & INDEX_NODE_PREFIX) {
215 struct buffer *buf = buf_create();
216 buf_freadchars(buf, in);
217 prefix = buf_detach(buf);
218 } else
219 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200220
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200221 if (offset & INDEX_NODE_CHILDS) {
222 char first = read_char(in);
223 char last = read_char(in);
224 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200225
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200226 node = NOFAIL(malloc(sizeof(struct index_node_f) +
227 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200228
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200229 node->first = first;
230 node->last = last;
231
232 for (i = 0; i < child_count; i++)
233 node->children[i] = read_long(in);
234 } else {
235 node = NOFAIL(malloc(sizeof(struct index_node_f)));
236 node->first = INDEX_CHILDMAX;
237 node->last = 0;
238 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200239
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200240 node->values = NULL;
241 if (offset & INDEX_NODE_VALUES) {
242 int value_count;
243 struct buffer *buf = buf_create();
244 const char *value;
245 unsigned int priority;
246
247 value_count = read_long(in);
248
249 while (value_count--) {
250 priority = read_long(in);
251 buf_freadchars(buf, in);
252 value = buf_str(buf);
253 add_value(&node->values, value, priority);
254 buf_clear(buf);
255 }
256 buf_destroy(buf);
257 }
258
259 node->prefix = prefix;
260 node->file = in;
261 return node;
262}
263
264static void index_close(struct index_node_f *node)
265{
266 free(node->prefix);
267 index_values_free(node->values);
268 free(node);
269}
270
271struct index_file {
272 FILE *file;
273 uint32_t root_offset;
274};
275
276/* Failures are silent; modprobe will fall back to text files */
277struct index_file *index_file_open(const char *filename)
278{
279 FILE *file;
280 uint32_t magic, version;
281 struct index_file *new;
282
283 file = fopen(filename, "r");
284 if (!file)
285 return NULL;
286 errno = EINVAL;
287
288 magic = read_long(file);
289 if (magic != INDEX_MAGIC)
290 return NULL;
291
292 version = read_long(file);
293 if (version >> 16 != INDEX_VERSION_MAJOR)
294 return NULL;
295
296 new = NOFAIL(malloc(sizeof(struct index_file)));
297 new->file = file;
298 new->root_offset = read_long(new->file);
299
300 errno = 0;
301 return new;
302}
303
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200304void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200305{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200306 fclose(idx->file);
307 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200308}
309
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200310static struct index_node_f *index_readroot(struct index_file *in)
311{
312 return index_read(in->file, in->root_offset);
313}
314
315static struct index_node_f *index_readchild(const struct index_node_f *parent,
316 int ch)
317{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200318 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200319 return index_read(parent->file,
320 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200321 }
322
323 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200324}
325
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200326static char *index_search__node(struct index_node_f *node, const char *key, int i)
327{
328 char *value;
329 struct index_node_f *child;
330 int ch;
331 int j;
332
333 while(node) {
334 for (j = 0; node->prefix[j]; j++) {
335 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200336
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200337 if (ch != key[i+j]) {
338 index_close(node);
339 return NULL;
340 }
341 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200342
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200343 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200344
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200345 if (key[i] == '\0') {
346 if (node->values) {
347 value = strdup(node->values[0].value);
348 index_close(node);
349 return value;
350 } else {
351 return NULL;
352 }
353 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200354
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200355 child = index_readchild(node, key[i]);
356 index_close(node);
357 node = child;
358 i++;
359 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200360
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200361 return NULL;
362}
363
364/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200365 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200366 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200367 * Returns the value of the first match
368 *
369 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200370 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200371char *index_search(struct index_file *in, const char *key)
372{
373 struct index_node_f *root;
374 char *value;
375
376 root = index_readroot(in);
377 value = index_search__node(root, key, 0);
378
379 return value;
380}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200381
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200382
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200383
384/* Level 4: add all the values from a matching node */
385static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200386 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200387{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200388 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200389
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200390 for (v = node->values; v != NULL; v = v->next)
391 add_value(out, v->value, v->priority);
392
393 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200394}
395
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200396/*
397 * Level 3: traverse a sub-keyspace which starts with a wildcard,
398 * looking for matches.
399 */
400static void index_searchwild__all(struct index_node_f *node, int j,
401 struct buffer *buf,
402 const char *subkey,
403 struct index_value **out)
404{
405 int pushed = 0;
406 int ch;
407
408 while (node->prefix[j]) {
409 ch = node->prefix[j];
410
411 buf_pushchar(buf, ch);
412 pushed++;
413 j++;
414 }
415
416 for (ch = node->first; ch <= node->last; ch++) {
417 struct index_node_f *child = index_readchild(node, ch);
418
419 if (!child)
420 continue;
421
422 buf_pushchar(buf, ch);
423 index_searchwild__all(child, 0, buf, subkey, out);
424 buf_popchar(buf);
425 }
426
427 if (node->values) {
428 if (fnmatch(buf_str(buf), subkey, 0) == 0)
429 index_searchwild__allvalues(node, out);
430 } else {
431 index_close(node);
432 }
433
434 buf_popchars(buf, pushed);
435}
436
437/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200438static void index_searchwild__node(struct index_node_f *node,
439 struct buffer *buf,
440 const char *key, int i,
441 struct index_value **out)
442{
443 struct index_node_f *child;
444 int j;
445 int ch;
446
447 while(node) {
448 for (j = 0; node->prefix[j]; j++) {
449 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200450
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200451 if (ch == '*' || ch == '?' || ch == '[') {
452 index_searchwild__all(node, j, buf,
453 &key[i+j], out);
454 return;
455 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200456
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200457 if (ch != key[i+j]) {
458 index_close(node);
459 return;
460 }
461 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200462
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200463 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200464
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200465 child = index_readchild(node, '*');
466 if (child) {
467 buf_pushchar(buf, '*');
468 index_searchwild__all(child, 0, buf, &key[i], out);
469 buf_popchar(buf);
470 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200471
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200472 child = index_readchild(node, '?');
473 if (child) {
474 buf_pushchar(buf, '?');
475 index_searchwild__all(child, 0, buf, &key[i], out);
476 buf_popchar(buf);
477 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200478
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200479 child = index_readchild(node, '[');
480 if (child) {
481 buf_pushchar(buf, '[');
482 index_searchwild__all(child, 0, buf, &key[i], out);
483 buf_popchar(buf);
484 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200485
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200486 if (key[i] == '\0') {
487 index_searchwild__allvalues(node, out);
488
489 return;
490 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200491
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200492 child = index_readchild(node, key[i]);
493 index_close(node);
494 node = child;
495 i++;
496 }
497}
498
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200499/*
500 * Search the index for a key. The index may contain wildcards.
501 *
502 * Returns a list of all the values of matching keys.
503 */
504struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200505{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200506 struct index_node_f *root = index_readroot(in);
507 struct buffer *buf = buf_create();
508 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200509
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200510 index_searchwild__node(root, buf, key, 0, &out);
511 buf_destroy(buf);
512 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200513}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200514
515#include <sys/mman.h>
516#include <sys/stat.h>
517#include <unistd.h>
518
519/**************************************************************************/
520/*
521 * Alternative implementation, using mmap to map all the file to memory when
522 * starting
523 */
524struct index_mm {
525 struct kmod_ctx *ctx;
526 void *mm;
527 uint32_t root_offset;
528 size_t size;
529};
530
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200531struct index_mm_node {
532 struct index_mm *idx;
533 char *prefix;
534 struct index_value *values;
535 unsigned char first;
536 unsigned char last;
537 uint32_t children[];
538};
539
540static inline uint32_t read_long_mm(void **p)
541{
542 uint32_t v = **((uint32_t **)p);
543
544 *p = *((uint8_t **)p) + sizeof(uint32_t);
545
546 return ntohl(v);
547}
548
549static inline uint8_t read_char_mm(void **p)
550{
551 uint8_t *v = *((uint8_t **)p);
552 *p = v + 1;
553 return *v;
554}
555
556static inline char *read_alloc_chars_mm(void **p)
557{
558 char *s = *((char **)p);
559 size_t len = strlen(s) + 1;
560 *p = ((char *)p) + len;
561
562 return memdup(s, len);
563}
564
565static inline char *read_chars_mm(void **p)
566{
567 char *s = *((char **)p);
568 size_t len = strlen(s) + 1;
569 *p = ((char *)p) + len;
570
571 return s;
572}
573
574static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
575 uint32_t offset) {
576 void *p = idx->mm;
577 struct index_mm_node *node;
578 char *prefix;
579 int i, child_count = 0;
580
581
582 if ((offset & INDEX_NODE_MASK) == 0)
583 return NULL;
584
585 p = (char *)p + (offset & INDEX_NODE_MASK);
586
587 if (offset & INDEX_NODE_PREFIX)
588 prefix = read_alloc_chars_mm(&p);
589 else
590 prefix = strdup("");
591
592 if (offset & INDEX_NODE_CHILDS) {
593 char first = read_char_mm(&p);
594 char last = read_char_mm(&p);
595 child_count = last - first + 1;
596
597 node = malloc(sizeof(*node) + sizeof(uint32_t) * child_count);
598
599 node->first = first;
600 node->last = last;
601
602 for (i = 0; i < child_count; i++)
603 node->children[i] = read_long_mm(&p);
604 } else {
605 node = malloc(sizeof(*node));
606 node->first = INDEX_CHILDMAX;
607 node->last = 0;
608 }
609
610 node->values = NULL;
611
612 if (offset & INDEX_NODE_VALUES) {
613 uint32_t j;
614
615 for (j = read_long_mm(&p); j > 0; j--) {
616 unsigned int priority;
617 const char *value;
618
619 priority = read_long_mm(&p);
620 value = read_chars_mm(&p);
621 add_value(&node->values, value, priority);
622 }
623 }
624
625 node->prefix = prefix;
626 node->idx = idx;
627
628 return node;
629}
630
631static void index_mm_free_node(struct index_mm_node *node)
632{
633 free(node->prefix);
634 index_values_free(node->values);
635 free(node);
636}
637
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200638struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
639{
640 int fd;
641 struct stat st;
642 struct index_mm *idx;
643 struct {
644 uint32_t magic;
645 uint32_t version;
646 uint32_t root_offset;
647 } hdr;
648 void *p;
649
650 DBG(ctx, "file=%s\n", filename);
651
652 if ((fd = open(filename, O_RDONLY)) < 0) {
653 ERR(ctx, "%m\n");
654 return NULL;
655 }
656
657 fstat(fd, &st);
658
659 idx = malloc(sizeof(*idx));
660 if (idx == NULL) {
661 ERR(ctx, "%m\n");
662 goto fail;
663 }
664
665 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
666 MAP_PRIVATE | MAP_POPULATE,
667 fd, 0)) == MAP_FAILED) {
668 ERR(ctx, "%m\n");
669 goto fail;
670 }
671
672 p = idx->mm;
673 hdr.magic = read_long_mm(&p);
674 hdr.version = read_long_mm(&p);
675 hdr.root_offset = read_long_mm(&p);
676
677 if (hdr.magic != INDEX_MAGIC) {
678 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
679 INDEX_MAGIC);
680 goto fail;
681 }
682
683 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
684 ERR(ctx, "major version check fail: %u instead of %u\n",
685 hdr.version, INDEX_MAGIC);
686 goto fail;
687 }
688
689 idx->root_offset = hdr.root_offset;
690 idx->size = st.st_size;
691 idx->ctx = ctx;
692 close(fd);
693
694 return idx;
695
696fail:
697 close(fd);
698 if (idx->mm)
699 munmap(idx->mm, st.st_size);
700 free(idx);
701 return NULL;
702}
703
704void index_mm_close(struct index_mm *idx)
705{
706 munmap(idx->mm, idx->size);
707 free(idx);
708}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200709
710static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
711{
712 return index_mm_read_node(idx, idx->root_offset);
713}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200714
715static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
716 int ch)
717{
718 if (parent->first <= ch && ch <= parent->last) {
719 return index_mm_read_node(parent->idx,
720 parent->children[ch - parent->first]);
721 }
722
723 return NULL;
724}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200725
726static char *index_mm_search_node(struct index_mm_node *node, const char *key,
727 int i)
728{
729 char *value;
730 struct index_mm_node *child;
731 int ch;
732 int j;
733
734 while(node) {
735 for (j = 0; node->prefix[j]; j++) {
736 ch = node->prefix[j];
737
738 if (ch != key[i+j]) {
739 index_mm_free_node(node);
740 return NULL;
741 }
742 }
743
744 i += j;
745
746 if (key[i] == '\0') {
747 if (node->values) {
748 value = strdup(node->values[0].value);
749 index_mm_free_node(node);
750 return value;
751 } else {
752 return NULL;
753 }
754 }
755
756 child = index_mm_readchild(node, key[i]);
757 index_mm_free_node(node);
758 node = child;
759 i++;
760 }
761
762 return NULL;
763}
Lucas De Marchib797b792011-12-02 17:49:03 -0200764
765/*
766 * Search the index for a key
767 *
768 * Returns the value of the first match
769 *
770 * The recursive functions free their node argument (using index_close).
771 */
772char *index_mm_search(struct index_mm *idx, const char *key)
773{
774 struct index_mm_node *root;
775 char *value;
776
777 root = index_mm_readroot(idx);
778 value = index_mm_search_node(root, key, 0);
779
780 return value;
781}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200782
783/* Level 4: add all the values from a matching node */
784static void index_mm_searchwild_allvalues(struct index_mm_node *node,
785 struct index_value **out)
786{
787 struct index_value *v;
788
789 for (v = node->values; v != NULL; v = v->next)
790 add_value(out, v->value, v->priority);
791
792 index_mm_free_node(node);
793}
794
795/*
796 * Level 3: traverse a sub-keyspace which starts with a wildcard,
797 * looking for matches.
798 */
799static void index_mm_searchwild_all(struct index_mm_node *node, int j,
800 struct buffer *buf,
801 const char *subkey,
802 struct index_value **out)
803{
804 int pushed = 0;
805 int ch;
806
807 while (node->prefix[j]) {
808 ch = node->prefix[j];
809
810 buf_pushchar(buf, ch);
811 pushed++;
812 j++;
813 }
814
815 for (ch = node->first; ch <= node->last; ch++) {
816 struct index_mm_node *child = index_mm_readchild(node, ch);
817
818 if (!child)
819 continue;
820
821 buf_pushchar(buf, ch);
822 index_mm_searchwild_all(child, 0, buf, subkey, out);
823 buf_popchar(buf);
824 }
825
826 if (node->values) {
827 if (fnmatch(buf_str(buf), subkey, 0) == 0)
828 index_mm_searchwild_allvalues(node, out);
829 } else {
830 index_mm_free_node(node);
831 }
832
833 buf_popchars(buf, pushed);
834}
835
836/* Level 2: descend the tree (until we hit a wildcard) */
837static void index_mm_searchwild_node(struct index_mm_node *node,
838 struct buffer *buf,
839 const char *key, int i,
840 struct index_value **out)
841{
842 struct index_mm_node *child;
843 int j;
844 int ch;
845
846 while(node) {
847 for (j = 0; node->prefix[j]; j++) {
848 ch = node->prefix[j];
849
850 if (ch == '*' || ch == '?' || ch == '[') {
851 index_mm_searchwild_all(node, j, buf,
852 &key[i+j], out);
853 return;
854 }
855
856 if (ch != key[i+j]) {
857 index_mm_free_node(node);
858 return;
859 }
860 }
861
862 i += j;
863
864 child = index_mm_readchild(node, '*');
865 if (child) {
866 buf_pushchar(buf, '*');
867 index_mm_searchwild_all(child, 0, buf, &key[i], out);
868 buf_popchar(buf);
869 }
870
871 child = index_mm_readchild(node, '?');
872 if (child) {
873 buf_pushchar(buf, '?');
874 index_mm_searchwild_all(child, 0, buf, &key[i], out);
875 buf_popchar(buf);
876 }
877
878 child = index_mm_readchild(node, '[');
879 if (child) {
880 buf_pushchar(buf, '[');
881 index_mm_searchwild_all(child, 0, buf, &key[i], out);
882 buf_popchar(buf);
883 }
884
885 if (key[i] == '\0') {
886 index_mm_searchwild_allvalues(node, out);
887
888 return;
889 }
890
891 child = index_mm_readchild(node, key[i]);
892 index_mm_free_node(node);
893 node = child;
894 i++;
895 }
896}
897
898/*
899 * Search the index for a key. The index may contain wildcards.
900 *
901 * Returns a list of all the values of matching keys.
902 */
903struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
904{
905 struct index_mm_node *root = index_mm_readroot(idx);
906 struct buffer *buf = buf_create();
907 struct index_value *out = NULL;
908
909 index_mm_searchwild_node(root, buf, key, 0, &out);
910 buf_destroy(buf);
911 return out;
912}