remove compile warning from modindex.c
[mit.git] / index.c
blob57c7684c8da24ba99704f49d56e555c28b7e64ab
1 /* index.c: module index file shared functions for modprobe and depmod
2 Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>.
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.
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.
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/>.
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <fnmatch.h>
24 #include "logging.h"
25 #include "index.h"
28 * Index abstract data type (used only by depmod)
31 struct index_node *index_create()
33 struct index_node *node;
35 node = NOFAIL(calloc(sizeof(struct index_node), 1));
36 node->prefix = NOFAIL(strdup(""));
37 node->first = INDEX_CHILDMAX;
39 return node;
42 void index_destroy(struct index_node *node)
44 int c;
46 for (c = node->first; c <= node->last; c++) {
47 struct index_node *child = node->children[c];
49 if (child)
50 index_destroy(child);
52 free(node->prefix);
53 free(node);
56 static void index__checkstring(const char *str)
58 int spaces = 0;
59 int i;
61 for (i = 0; str[i]; i++) {
62 int ch = str[i];
64 if (ch >= INDEX_CHILDMAX)
65 fatal("Module index: bad character '%c'=0x%x - only 7-bit ASCII is supported:"
66 "\n%s\n", (char) ch, (int) ch, str);
68 if (ch == ' ')
69 spaces++;
72 if (!spaces)
73 fatal("Module index: internal error - missing space (key/value separator)"
74 "\n%s\n", str);
77 int index_insert(struct index_node *node, const char *str)
79 int i = 0; /* index within str */
80 int ch;
81 int duplicate = 0;
83 index__checkstring(str);
85 while(1) {
86 int j; /* index within node->prefix */
88 /* Ensure node->prefix is a prefix of &str[i].
89 If it is not already, then we must split node. */
90 for (j = 0; node->prefix[j]; j++) {
91 ch = node->prefix[j];
93 if (ch != str[i+j]) {
94 char *prefix = node->prefix;
95 struct index_node *n;
97 /* New child is copy of node with prefix[j+1..N] */
98 n = NOFAIL(calloc(sizeof(struct index_node), 1));
99 memcpy(n, node, sizeof(struct index_node));
100 n->prefix = NOFAIL(strdup(&prefix[j+1]));
102 /* Parent has prefix[0..j], child at prefix[j] */
103 memset(node, 0, sizeof(struct index_node));
104 prefix[j] = '\0';
105 node->prefix = prefix;
106 node->first = ch;
107 node->last = ch;
108 node->children[ch] = n;
110 break;
113 /* j is now length of node->prefix */
114 i += j;
116 ch = str[i];
117 if(ch == '\0') {
118 if (node->isendpoint)
119 duplicate = 1;
121 node->isendpoint = 1;
122 return duplicate;
125 if (!node->children[ch]) {
126 struct index_node *child;
128 if (ch < node->first)
129 node->first = ch;
130 if (ch > node->last)
131 node->last = ch;
132 node->children[ch] = NOFAIL(calloc(sizeof(struct index_node), 1));
134 child = node->children[ch];
135 child->prefix = NOFAIL(strdup(&str[i+1]));
136 child->isendpoint = 1;
137 child->first = INDEX_CHILDMAX;
139 return duplicate;
142 /* Descend into child node and continue */
143 node = node->children[ch];
144 i++;
148 static int index__haschildren(const struct index_node *node)
150 return node->first < INDEX_CHILDMAX;
153 /* Recursive post-order traversal
155 Pre-order would make for better read-side buffering / readahead / caching.
156 (post-order means you go backwards in the file as you descend the tree).
157 However, index reading is already fast enough.
158 Pre-order is simpler for writing, and depmod is already slow.
160 static uint32_t index_write__node(const struct index_node *node, FILE *out)
162 uint32_t *child_offs = NULL;
163 int child_count = 0;
164 long offset;
166 if (!node)
167 return 0;
169 /* Write children and save their offsets */
170 if (index__haschildren(node)) {
171 const struct index_node *child;
172 int i;
174 child_count = node->last - node->first + 1;
175 child_offs = NOFAIL(malloc(child_count * sizeof(uint32_t)));
177 for (i = 0; i < child_count; i++) {
178 child = node->children[node->first + i];
179 child_offs[i] = htonl(index_write__node(child, out));
183 /* Now write this node */
184 offset = ftell(out);
186 if (node->prefix[0]) {
187 fputs(node->prefix, out);
188 fputc('\0', out);
189 offset |= INDEX_NODE_PREFIX;
192 if (child_count) {
193 fputc(node->first, out);
194 fputc(node->last, out);
195 fwrite(child_offs, sizeof(uint32_t), child_count, out);
196 free(child_offs);
197 offset |= INDEX_NODE_CHILDS;
200 if (node->isendpoint)
201 offset |= INDEX_NODE_ENDPOINT;
203 return offset;
206 void index_write(const struct index_node *node, FILE *out)
208 long initial_offset, final_offset;
209 uint32_t u;
211 u = htonl(INDEX_MAGIC);
212 fwrite(&u, sizeof(u), 1, out);
214 /* First word is reserved for the offset of the root node */
215 initial_offset = ftell(out);
216 u = 0;
217 fwrite(&u, sizeof(uint32_t), 1, out);
219 /* Dump trie */
220 u = htonl(index_write__node(node, out));
222 /* Update first word */
223 final_offset = ftell(out);
224 fseek(out, initial_offset, SEEK_SET);
225 fwrite(&u, sizeof(uint32_t), 1, out);
226 fseek(out, final_offset, SEEK_SET);
231 static void read_error()
233 fatal("Module index: unexpected error: %s\n"
234 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
237 static int read_char(FILE *in)
239 int ch;
241 errno = 0;
242 ch = getc_unlocked(in);
243 if (ch == EOF)
244 read_error();
245 return ch;
248 static uint32_t read_long(FILE *in)
250 uint32_t l;
252 errno = 0;
253 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
254 read_error();
255 return ntohl(l);
259 * Buffer abstract data type
261 * Used internally to store the current path during tree traversal.
262 * They help build wildcard key strings to pass to fnmatch(),
263 * as well as building values of matching keys.
266 struct buffer {
267 char *bytes;
268 unsigned size;
269 unsigned used;
272 static void buf__realloc(struct buffer *buf, unsigned size)
274 if (size > buf->size) {
275 buf->bytes = NOFAIL(realloc(buf->bytes, size));
276 buf->size = size;
280 static struct buffer *buf_create()
282 struct buffer *buf;
284 buf = NOFAIL(calloc(sizeof(struct buffer), 1));
285 buf__realloc(buf, 256);
286 return buf;
289 static void buf_destroy(struct buffer *buf)
291 free(buf->bytes);
292 free(buf);
295 /* Destroy buffer and return a copy as a C string */
296 static char *buf_detach(struct buffer *buf)
298 char *bytes;
300 bytes = NOFAIL(realloc(buf->bytes, buf->used + 1));
301 bytes[buf->used] = '\0';
303 free(buf);
304 return bytes;
307 /* Return a C string owned by the buffer
308 (invalidated if the buffer is changed).
310 static const char *buf_str(struct buffer *buf)
312 buf__realloc(buf, buf->used + 1);
313 buf->bytes[buf->used] = '\0';
314 return buf->bytes;
317 static int buf_fwrite(struct buffer *buf, FILE *out)
319 return fwrite(buf->bytes, 1, buf->used, out);
322 static struct index_value *add_value(struct buffer *buf,
323 struct index_value *values)
325 struct index_value *n = malloc(sizeof(struct index_value) + buf->used + 1);
327 memcpy(n->value, buf->bytes, buf->used);
328 n->value[buf->used] = '\0';
329 n->next = values;
331 return n;
334 static void buf_popchars(struct buffer *buf, unsigned n)
336 buf->used -= n;
339 static void buf_pushchar(struct buffer *buf, char ch)
341 buf__realloc(buf, buf->used + 1);
342 buf->bytes[buf->used] = ch;
343 buf->used++;
346 static unsigned buf_pushchars(struct buffer *buf, const char *str)
348 unsigned i = 0;
349 int ch;
351 while ((ch = str[i])) {
352 buf_pushchar(buf, ch);
353 i++;
355 return i;
358 /* like buf_pushchars(), but the string comes from a file */
359 static unsigned buf_freadchars(struct buffer *buf, FILE *in)
361 unsigned i = 0;
362 int ch;
364 while ((ch = read_char(in))) {
365 buf_pushchar(buf, ch);
366 i++;
369 return i;
372 static void buf_popchar(struct buffer *buf)
374 buf->used--;
378 * Index file searching (used only by modprobe)
381 struct index_node_f {
382 FILE *file;
383 char *prefix; /* path compression */
384 char isendpoint; /* does this node represent a string? */
385 unsigned char first; /* range of child nodes */
386 unsigned char last;
387 uint32_t children[0];
390 static void index_fatal(const char *why)
392 fatal("Module index corrupt: %s\n"
393 "Try re-running depmod\n", why);
396 static struct index_node_f *index_read(FILE *in, uint32_t offset)
398 struct index_node_f *node;
399 char *prefix;
400 int i, child_count = 0;
402 if ((offset & INDEX_NODE_MASK) == 0)
403 return NULL;
405 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
407 if (offset & INDEX_NODE_PREFIX) {
408 struct buffer *buf = buf_create();
409 buf_freadchars(buf, in);
410 prefix = buf_detach(buf);
411 } else
412 prefix = NOFAIL(strdup(""));
414 if (offset & INDEX_NODE_CHILDS) {
415 char first = read_char(in);
416 char last = read_char(in);
417 child_count = last - first + 1;
419 node = NOFAIL(malloc(sizeof(struct index_node_f) +
420 sizeof(uint32_t) * child_count));
422 node->first = first;
423 node->last = last;
425 for (i = 0; i < child_count; i++)
426 node->children[i] = read_long(in);
427 } else {
428 node = NOFAIL(malloc(sizeof(struct index_node_f)));
429 node->first = INDEX_CHILDMAX;
430 node->last = 0;
433 node->prefix = prefix;
434 node->isendpoint = !!(offset & INDEX_NODE_ENDPOINT);
435 node->file = in;
436 return node;
439 static void index_close(struct index_node_f *node)
441 free(node->prefix);
442 free(node);
445 static struct index_node_f *index_readchild(const struct index_node_f *parent,
446 int ch)
448 if (parent->first <= ch && ch <= parent->last)
449 return index_read(parent->file,
450 parent->children[ch - parent->first]);
451 else
452 return NULL;
455 static struct index_node_f *index_readroot(FILE *in)
457 uint32_t offset;
459 fseek(in, 0, SEEK_SET);
461 if (read_long(in) != INDEX_MAGIC)
462 index_fatal("Bad magic number");
464 offset = read_long(in);
465 return index_read(in, offset);
469 * Dump all strings as lines in a plain text file.
472 static void index_dump_node(struct index_node_f *node,
473 struct buffer *buf,
474 FILE *out,
475 const char *prefix)
477 int ch, pushed;
479 pushed = buf_pushchars(buf, node->prefix);
481 if (node->isendpoint) {
482 fputs(prefix, out);
483 buf_fwrite(buf, out);
484 fputc('\n', out);
487 for (ch = node->first; ch <= node->last; ch++) {
488 struct index_node_f *child = index_readchild(node, ch);
490 if (!child)
491 continue;
493 buf_pushchar(buf, ch);
494 index_dump_node(child, buf, out, prefix);
495 buf_popchar(buf);
498 buf_popchars(buf, pushed);
499 index_close(node);
502 void index_dump(FILE *in, FILE *out, const char *prefix)
504 struct index_node_f *root;
505 struct buffer *buf;
507 buf = buf_create();
508 root = index_readroot(in);
509 index_dump_node(root, buf, out, prefix);
510 buf_destroy(buf);
514 * Search the index for a key
516 * Returns the value of the first match
518 * The calling convention for the inner functions
519 * is for the callee to free the node argument (using index_close).
522 /* Level 1: interface function */
523 char *index_search(FILE *in, const char *key);
525 /* Level 2: descend the tree */
526 static char *index_search__node(struct index_node_f *node, const char *key, int i);
528 /* Level 3: return the first value in the subtree.
529 The first character of the value is node->prefix[j] */
530 static char *index_search__firstvalue(struct index_node_f *node, int j);
532 char *index_search(FILE *in, const char *key)
534 struct index_node_f *root;
535 char *value;
537 root = index_readroot(in);
538 value = index_search__node(root, key, 0);
540 return value;
543 static char *index_search__node(struct index_node_f *node, const char *key, int i)
545 struct index_node_f *child;
546 int ch;
547 int j;
549 while(node) {
550 for (j = 0; node->prefix[j]; j++) {
551 ch = node->prefix[j];
553 if (ch == ' ' && key[i+j] == '\0')
554 return index_search__firstvalue(node, j+1);
556 if (ch != key[i+j]) {
557 index_close(node);
558 return NULL;
561 i += j;
563 if (key[i] == '\0') {
564 child = index_readchild(node, ' ');
565 index_close(node);
566 if (child)
567 return index_search__firstvalue(child, 0);
568 else
569 return NULL;
572 child = index_readchild(node, key[i]);
573 index_close(node);
574 node = child;
575 i++;
578 return NULL;
581 static char *index_search__firstvalue(struct index_node_f *node, int j)
583 struct index_node_f *child;
584 struct buffer *buf;
586 buf = buf_create();
587 buf_pushchars(buf, &node->prefix[j]);
589 while (!node->isendpoint) {
590 if (node->first == INDEX_CHILDMAX)
591 index_fatal("Index node is neither parent nor endpoint");
593 buf_pushchar(buf, node->first);
594 child = index_readchild(node, node->first);
595 index_close(node);
596 node = child;
597 if (!node)
598 index_fatal("Index node has non-existent first child");
600 buf_pushchars(buf, node->prefix);
603 index_close(node);
604 return buf_detach(buf);
608 * Search the index for a key. The index may contain wildcards.
610 * Returns a list of all the values of matching keys.
613 /* Level 1: interface function */
614 struct index_value *index_searchwild(FILE *in, const char *key);
616 /* Level 2: descend the tree (until we hit a wildcard) */
617 static void index_searchwild__node(struct index_node_f *node,
618 struct buffer *buf,
619 const char *key, int i,
620 struct index_value **out);
622 /* Level 3: traverse a sub-keyspace which starts with a wildcard,
623 generating all subkeys.
625 static void index_searchwild__all(struct index_node_f *node, int j,
626 struct buffer *buf,
627 const char *subkey,
628 struct index_value **out);
630 /* Level 4: check for a subkey match */
631 static void index_searchwild__match(struct index_node_f *node, int j,
632 struct buffer *buf,
633 const char *subkey,
634 struct index_value **out);
636 /* Level 5: add all values for a matching subkey */
637 static void index_searchwild__allvalues(struct index_node_f *node, int j,
638 struct buffer *value_buf,
639 struct index_value **out);
642 struct index_value *index_searchwild(FILE *in, const char *key)
644 struct index_node_f *root = index_readroot(in);
645 struct buffer *buf = buf_create();
646 struct index_value *out = NULL;
648 index_searchwild__node(root, buf, key, 0, &out);
649 buf_destroy(buf);
650 return out;
653 static void index_searchwild__node(struct index_node_f *node,
654 struct buffer *buf,
655 const char *key, int i,
656 struct index_value **out)
658 struct index_node_f *child;
659 int j;
660 int ch;
662 while(node) {
663 for (j = 0; node->prefix[j]; j++) {
664 ch = node->prefix[j];
666 if (ch == '*' || ch == '?' || ch == '[') {
667 index_searchwild__all(node, j, buf,
668 &key[i+j], out);
669 return;
672 if (ch == ' ' && key[i+j] == '\0') {
673 /* Note: buf matches &key[i+j] - both are empty */
674 index_searchwild__match(node, j+1, buf,
675 &key[i+j], out);
676 return;
679 if (ch != key[i+j]) {
680 index_close(node);
681 return;
684 i += j;
686 child = index_readchild(node, '*');
687 if (child) {
688 buf_pushchar(buf, '*');
689 index_searchwild__all(child, 0, buf, &key[i], out);
690 buf_popchar(buf);
693 child = index_readchild(node, '?');
694 if (child) {
695 buf_pushchar(buf, '*');
696 index_searchwild__all(child, 0, buf, &key[i], out);
697 buf_popchar(buf);
700 child = index_readchild(node, '[');
701 if (child) {
702 buf_pushchar(buf, '[');
703 index_searchwild__all(child, 0, buf, &key[i], out);
704 buf_popchar(buf);
707 if (key[i] == '\0') {
708 child = index_readchild(node, ' ');
709 index_close(node);
710 /* Note: buf matches &key[i] - both are empty */
711 if(child)
712 index_searchwild__match(child, 0,
713 buf, &key[i], out);
714 return;
717 child = index_readchild(node, key[i]);
718 index_close(node);
719 node = child;
720 i++;
724 static void index_searchwild__all(struct index_node_f *node, int j,
725 struct buffer *buf,
726 const char *subkey,
727 struct index_value **out)
729 int pushed = 0;
730 int ch;
732 while (node->prefix[j]) {
733 ch = node->prefix[j];
735 if (ch == ' ') {
736 index_searchwild__match(node, j+1, buf, subkey, out);
737 goto out_popchars;
739 buf_pushchar(buf, ch);
740 pushed++;
741 j++;
744 for (ch = node->first; ch <= node->last; ch++) {
745 struct index_node_f *child = index_readchild(node, ch);
747 if (!child)
748 continue;
750 if (ch == ' ') {
751 index_searchwild__match(child, 0, buf, subkey, out);
752 } else {
753 buf_pushchar(buf, ch);
754 index_searchwild__all(child, 0, buf, subkey, out);
755 buf_popchar(buf);
759 index_close(node);
761 out_popchars:
762 buf_popchars(buf, pushed);
765 static void index_searchwild__match(struct index_node_f *node, int j,
766 struct buffer *buf,
767 const char *subkey,
768 struct index_value **out)
770 struct buffer *value_buf;
771 const char *pattern;
773 pattern = buf_str(buf);
774 if (fnmatch(pattern, subkey, 0) == 0) {
775 value_buf = buf_create();
776 index_searchwild__allvalues(node, j, value_buf, out);
777 buf_destroy(value_buf);
778 } else
779 index_close(node);
782 static void index_searchwild__allvalues(struct index_node_f *node, int j,
783 struct buffer *value_buf,
784 struct index_value **out)
786 int pushed = 0;
787 int ch;
789 pushed = buf_pushchars(value_buf, &node->prefix[j]);
791 if (node->isendpoint)
792 *out = add_value(value_buf, *out);
794 for (ch = node->first; ch <= node->last; ch++) {
795 struct index_node_f *child = index_readchild(node, ch);
797 if (!child)
798 continue;
800 buf_pushchar(value_buf, ch);
801 index_searchwild__allvalues(child, 0, value_buf, out);
802 buf_popchar(value_buf);
805 index_close(node);
806 buf_popchars(value_buf, pushed);