libselinux: label_file: use PCRE instead of glibc regex functions

The PCRE functions are about x10 faster than the glibc functions.  So
use the external library.

Signed-off-by: Eric Paris <eparis@redhat.com>
This commit is contained in:
Eric Paris 2012-08-22 11:43:29 -04:00
parent ac5f5645b6
commit 091eb526dd
2 changed files with 35 additions and 30 deletions

View file

@ -20,6 +20,8 @@ RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER))
RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM)
LIBBASE=$(shell basename $(LIBDIR))
LDFLAGS ?= -lpcre
VERSION = $(shell cat ../VERSION)
LIBVERSION = 1

View file

@ -16,7 +16,7 @@
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <regex.h>
#include <pcre.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -32,7 +32,8 @@ typedef struct spec {
struct selabel_lookup_rec lr; /* holds contexts for lookup result */
char *regex_str; /* regular expession string for diagnostics */
char *type_str; /* type string for diagnostic messages */
regex_t regex; /* compiled regular expression */
pcre *regex; /* compiled regular expression */
pcre_extra *sd; /* extra compiled stuff */
char regcomp; /* regex_str has been compiled to regex */
mode_t mode; /* mode format value */
int matches; /* number of matching pathnames */
@ -223,12 +224,13 @@ static void spec_hasMetaChars(struct spec *spec)
return;
}
static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
static int compile_regex(struct saved_data *data, spec_t *spec, const char **errbuf)
{
const char *tmperrbuf;
char *reg_buf, *anchored_regex, *cp;
stem_t *stem_arr = data->stem_arr;
size_t len;
int regerr;
int erroff;
if (spec->regcomp)
return 0; /* already done */
@ -245,6 +247,7 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
cp = anchored_regex = malloc(len + 3);
if (!anchored_regex)
return -1;
/* Create ^...$ regexp. */
*cp++ = '^';
cp = mempcpy(cp, reg_buf, len);
@ -252,21 +255,20 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
*cp = '\0';
/* Compile the regular expression. */
regerr = regcomp(&spec->regex, anchored_regex,
REG_EXTENDED | REG_NOSUB);
if (regerr != 0) {
size_t errsz = 0;
errsz = regerror(regerr, &spec->regex, NULL, 0);
if (errsz && errbuf)
*errbuf = malloc(errsz);
if (errbuf && *errbuf)
(void)regerror(regerr, &spec->regex,
*errbuf, errsz);
free(anchored_regex);
spec->regex = pcre_compile(anchored_regex, 0, &tmperrbuf, &erroff, NULL);
free(anchored_regex);
if (!spec->regex) {
if (errbuf)
*errbuf=tmperrbuf;
return -1;
}
spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
if (!spec->sd) {
if (errbuf)
*errbuf=tmperrbuf;
return -1;
}
free(anchored_regex);
/* Done. */
spec->regcomp = 1;
@ -320,7 +322,7 @@ static int process_line(struct selabel_handle *rec,
if (pass == 1) {
/* On the second pass, process and store the specification in spec. */
char *errbuf = NULL;
const char *errbuf = NULL;
spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
spec_arr[nspec].regex_str = regex;
if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
@ -575,7 +577,10 @@ static void closef(struct selabel_handle *rec)
free(spec->type_str);
free(spec->lr.ctx_raw);
free(spec->lr.ctx_trans);
regfree(&spec->regex);
if (spec->regcomp) {
pcre_free(spec->regex);
pcre_free_study(spec->sd);
}
}
for (i = 0; i < (unsigned int)data->num_stems; i++) {
@ -634,26 +639,24 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
* the last matching specification is used.
*/
for (i = data->nspec - 1; i >= 0; i--) {
spec_t *spec = &spec_arr[i];
/* if the spec in question matches no stem or has the same
* stem as the file AND if the spec in question has no mode
* specified or if the mode matches the file mode then we do
* a regex check */
if ((spec_arr[i].stem_id == -1
|| spec_arr[i].stem_id == file_stem)
&& (!mode || !spec_arr[i].mode
|| mode == spec_arr[i].mode)) {
if (compile_regex(data, &spec_arr[i], NULL) < 0)
if ((spec->stem_id == -1 || spec->stem_id == file_stem) &&
(!mode || !spec->mode || mode == spec->mode)) {
if (compile_regex(data, spec, NULL) < 0)
goto finish;
if (spec_arr[i].stem_id == -1)
rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
if (spec->stem_id == -1)
rc = pcre_exec(spec->regex, spec->sd, key, strlen(key), 0, 0, NULL, 0);
else
rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
rc = pcre_exec(spec->regex, spec->sd, buf, strlen(buf), 0, 0, NULL, 0);
if (rc == 0) {
spec_arr[i].matches++;
spec->matches++;
break;
}
if (rc == REG_NOMATCH)
} else if (rc == PCRE_ERROR_NOMATCH)
continue;
/* else it's an error */
goto finish;