X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;ds=sidebyside;f=filters.c;h=6ed7751dea230c65e55dd3e4da9ad9b143a2f657;hb=a78917cb6bdd684e01a1a293e68d64ebe57d52ff;hp=2aeacbf1d60b1041098d3af5b98150595dbdf41c;hpb=6725db54d5b7faf133af69f3d63d71175685cf75;p=obnox%2Fwireshark%2Fwip.git diff --git a/filters.c b/filters.c index 2aeacbf1d6..6ed7751dea 100644 --- a/filters.c +++ b/filters.c @@ -1,23 +1,22 @@ /* filters.c * Code for reading and writing the filters file. * - * $Id: filters.c,v 1.3 2001/01/28 09:13:07 guy Exp $ + * $Id$ * - * Ethereal - Network traffic analyzer - * By Gerald Combs + * Wireshark - Network traffic analyzer + * By Gerald Combs * Copyright 1998 Gerald Combs * - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -32,20 +31,16 @@ #include #include -#ifdef HAVE_SYS_STAT_H -#include -#endif - #ifdef HAVE_UNISTD_H #include #endif #include -#include +#include #include "filters.h" -#include "util.h" +#include /* * Old filter file name. @@ -62,18 +57,26 @@ */ #define DFILTER_FILE_NAME "dfilters" -#define FILTER_LINE_SIZE 2048 - /* - * List of capture filters. + * List of capture filters - saved. */ static GList *capture_filters = NULL; /* - * List of display filters. + * List of display filters - saved. */ static GList *display_filters = NULL; +/* + * List of capture filters - currently edited. + */ +static GList *capture_edited_filters = NULL; + +/* + * List of display filters - currently edited. + */ +static GList *display_edited_filters = NULL; + /* * Read in a list of filters. * @@ -82,31 +85,58 @@ static GList *display_filters = NULL; * the file we tried to read - it should be freed by our caller - * and "*errno_return" is set to the error. */ + +#define INIT_BUF_SIZE 128 + +static GList * +add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr) +{ + filter_def *filt; + + filt = (filter_def *) g_malloc(sizeof(filter_def)); + filt->name = g_strdup(filt_name); + filt->strval = g_strdup(filt_expr); + return g_list_append(fl, filt); +} + +static GList * +remove_filter_entry(GList *fl, GList *fl_entry) +{ + filter_def *filt; + + filt = (filter_def *) fl_entry->data; + g_free(filt->name); + g_free(filt->strval); + g_free(filt); + return g_list_remove_link(fl, fl_entry); +} + void -read_filter_list(filter_list_type_t list, char **pref_path_return, +read_filter_list(filter_list_type_t list_type, char **pref_path_return, int *errno_return) { - char *ff_path, *ff_dir = PF_DIR, *ff_name; + const char *ff_name; + char *ff_path; FILE *ff; - GList **flp; - GList *fl_ent; - filter_def *filt; - char f_buf[FILTER_LINE_SIZE]; - char *name_begin, *name_end, *filt_begin; - int len, line = 0; + GList **flpp; + int c; + char *filt_name, *filt_expr; + int filt_name_len, filt_expr_len; + int filt_name_index, filt_expr_index; + int line = 1; *pref_path_return = NULL; /* assume no error */ - switch (list) { + switch (list_type) { case CFILTER_LIST: ff_name = CFILTER_FILE_NAME; - flp = &capture_filters; + flpp = &capture_filters; break; case DFILTER_LIST: ff_name = DFILTER_FILE_NAME; - flp = &display_filters; + flpp = &display_filters; break; default: @@ -114,14 +144,11 @@ read_filter_list(filter_list_type_t list, char **pref_path_return, return; } - /* To do: generalize this */ - ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) + - strlen(ff_name) + 4); - sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name); - - if ((ff = fopen(ff_path, "r")) == NULL) { + /* try to open personal "cfilters"/"dfilters" file */ + ff_path = get_persconffile_path(ff_name, TRUE, FALSE); + if ((ff = ws_fopen(ff_path, "r")) == NULL) { /* - * Did that fail because we the file didn't exist? + * Did that fail because the file didn't exist? */ if (errno != ENOENT) { /* @@ -133,71 +160,200 @@ read_filter_list(filter_list_type_t list, char **pref_path_return, } /* - * Yes. See if there's a "filters" file; if so, read it. + * Yes. See if there's an "old style" personal "filters" file; if so, read it. * This means that a user will start out with their capture and * display filter lists being identical; each list may contain * filters that don't belong in that list. The user can edit * the filter lists, and delete the ones that don't belong in * a particular list. */ - sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, FILTER_FILE_NAME); - if ((ff = fopen(ff_path, "r")) == NULL) { + g_free(ff_path); + ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE, FALSE); + if ((ff = ws_fopen(ff_path, "r")) == NULL) { /* - * Well, that didn't work, either. Just give up. - * Return an error if the file existed but we couldn't open it. + * Did that fail because the file didn't exist? */ - if (errno != ENOENT) { - *pref_path_return = ff_path; - *errno_return = errno; + if (errno != ENOENT) { + /* + * No. Just give up. + */ + *pref_path_return = ff_path; + *errno_return = errno; + return; + } + + /* + * Try to open the global "cfilters/dfilters" file */ + g_free(ff_path); + ff_path = get_datafile_path(ff_name); + if ((ff = ws_fopen(ff_path, "r")) == NULL) { + + /* + * Well, that didn't work, either. Just give up. + * Return an error if the file existed but we couldn't open it. + */ + if (errno != ENOENT) { + *pref_path_return = ff_path; + *errno_return = errno; + } else { + g_free(ff_path); + } + return; } - return; } } /* If we already have a list of filters, discard it. */ - if (*flp != NULL) { - fl_ent = g_list_first(*flp); - while (fl_ent != NULL) { - filt = (filter_def *) fl_ent->data; - g_free(filt->name); - g_free(filt->strval); - g_free(filt); - fl_ent = fl_ent->next; - } - g_list_free(*flp); - *flp = NULL; + /* this should never happen - this function is called only once for each list! */ + while(*flpp) { + *flpp = remove_filter_entry(*flpp, g_list_first(*flpp)); } - while (fgets(f_buf, FILTER_LINE_SIZE, ff)) { - line++; - len = strlen(f_buf); - if (f_buf[len - 1] == '\n') { - len--; - f_buf[len] = '\0'; + /* Allocate the filter name buffer. */ + filt_name_len = INIT_BUF_SIZE; + filt_name = (char *)g_malloc(filt_name_len + 1); + filt_expr_len = INIT_BUF_SIZE; + filt_expr = (char *)g_malloc(filt_expr_len + 1); + + for (line = 1; ; line++) { + /* Lines in a filter file are of the form + + "name" expression + + where "name" is a name, in quotes - backslashes in the name + escape the next character, so quotes and backslashes can appear + in the name - and "expression" is a filter expression, not in + quotes, running to the end of the line. */ + + /* Skip over leading white space, if any. */ + while ((c = getc(ff)) != EOF && isspace(c)) { + if (c == '\n') { + /* Blank line. */ + continue; + } } - name_begin = strchr(f_buf, '"'); - /* Empty line */ - if (name_begin == NULL) + + if (c == EOF) + break; /* Nothing more to read */ + + /* "c" is the first non-white-space character. + If it's not a quote, it's an error. */ + if (c != '"') { + g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path, + line); + while (c != '\n') + c = getc(ff); /* skip to the end of the line */ continue; - name_end = strchr(name_begin + 1, '"'); - /* No terminating quote */ - if (name_end == NULL) { - g_warning("Malformed filter in '%s' line %d.", ff_path, line); + } + + /* Get the name of the filter. */ + filt_name_index = 0; + for (;;) { + c = getc(ff); + if (c == EOF || c == '\n') + break; /* End of line - or end of file */ + if (c == '"') { + /* Closing quote. */ + if (filt_name_index >= filt_name_len) { + /* Filter name buffer isn't long enough; double its length. */ + filt_name_len *= 2; + filt_name = (char *)g_realloc(filt_name, filt_name_len + 1); + } + filt_name[filt_name_index] = '\0'; + break; + } + if (c == '\\') { + /* Next character is escaped */ + c = getc(ff); + if (c == EOF || c == '\n') + break; /* End of line - or end of file */ + } + /* Add this character to the filter name string. */ + if (filt_name_index >= filt_name_len) { + /* Filter name buffer isn't long enough; double its length. */ + filt_name_len *= 2; + filt_name = (char *)g_realloc(filt_name, filt_name_len + 1); + } + filt_name[filt_name_index] = c; + filt_name_index++; + } + + if (c == EOF) { + if (!ferror(ff)) { + /* EOF, not error; no newline seen before EOF */ + g_warning("'%s' line %d doesn't have a newline.", ff_path, + line); + } + break; /* nothing more to read */ + } + + if (c != '"') { + /* No newline seen before end-of-line */ + g_warning("'%s' line %d doesn't have a closing quote.", ff_path, + line); continue; } - name_begin++; - name_end[0] = '\0'; - filt_begin = name_end + 1; - while(isspace((guchar)filt_begin[0])) filt_begin++; - /* No filter string */ - if (filt_begin[0] == '\0') { - g_warning("Malformed filter in '%s' line %d.", ff_path, line); + + /* Skip over separating white space, if any. */ + while ((c = getc(ff)) != EOF && isspace(c)) { + if (c == '\n') + break; + } + + if (c == EOF) { + if (!ferror(ff)) { + /* EOF, not error; no newline seen before EOF */ + g_warning("'%s' line %d doesn't have a newline.", ff_path, + line); + } + break; /* nothing more to read */ + } + + if (c == '\n') { + /* No filter expression */ + g_warning("'%s' line %d doesn't have a filter expression.", ff_path, + line); continue; } - filt = (filter_def *) g_malloc(sizeof(filter_def)); - filt->name = g_strdup(name_begin); - filt->strval = g_strdup(filt_begin); - *flp = g_list_append(*flp, filt); + + /* "c" is the first non-white-space character; it's the first + character of the filter expression. */ + filt_expr_index = 0; + for (;;) { + /* Add this character to the filter expression string. */ + if (filt_expr_index >= filt_expr_len) { + /* Filter expressioin buffer isn't long enough; double its length. */ + filt_expr_len *= 2; + filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1); + } + filt_expr[filt_expr_index] = c; + filt_expr_index++; + + /* Get the next character. */ + c = getc(ff); + if (c == EOF || c == '\n') + break; + } + + if (c == EOF) { + if (!ferror(ff)) { + /* EOF, not error; no newline seen before EOF */ + g_warning("'%s' line %d doesn't have a newline.", ff_path, + line); + } + break; /* nothing more to read */ + } + + /* We saw the ending newline; terminate the filter expression string */ + if (filt_expr_index >= filt_expr_len) { + /* Filter expressioin buffer isn't long enough; double its length. */ + filt_expr_len *= 2; + filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1); + } + filt_expr[filt_expr_index] = '\0'; + + /* Add the new filter to the list of filters */ + *flpp = add_filter_entry(*flpp, filt_name, filt_expr); } if (ferror(ff)) { *pref_path_return = ff_path; @@ -205,43 +361,66 @@ read_filter_list(filter_list_type_t list, char **pref_path_return, } else g_free(ff_path); fclose(ff); + g_free(filt_name); + g_free(filt_expr); + + /* init the corresponding edited list */ + switch (list_type) { + case CFILTER_LIST: + copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST); + break; + case DFILTER_LIST: + copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST); + break; + default: + g_assert_not_reached(); + return; + } } /* * Get a pointer to a list of filters. */ static GList ** -get_filter_list(filter_list_type_t list) +get_filter_list(filter_list_type_t list_type) { - GList **flp; + GList **flpp; - switch (list) { + switch (list_type) { case CFILTER_LIST: - flp = &capture_filters; + flpp = &capture_filters; break; case DFILTER_LIST: - flp = &display_filters; + flpp = &display_filters; + break; + + case CFILTER_EDITED_LIST: + flpp = &capture_edited_filters; + break; + + case DFILTER_EDITED_LIST: + flpp = &display_edited_filters; break; default: g_assert_not_reached(); - flp = NULL; + flpp = NULL; } - return flp; + return flpp; } /* * Get a pointer to the first entry in a filter list. */ GList * -get_filter_list_first(filter_list_type_t list) +get_filter_list_first(filter_list_type_t list_type) { - GList **flp; - - flp = get_filter_list(list); - return g_list_first(*flp); + GList **flpp; + + flpp = get_filter_list(list_type); + return g_list_first(*flpp); } /* @@ -249,34 +428,27 @@ get_filter_list_first(filter_list_type_t list) * Returns a pointer to the newly-added entry. */ GList * -add_to_filter_list(filter_list_type_t list, char *name, char *expression) +add_to_filter_list(filter_list_type_t list_type, const char *name, + const char *expression) { - GList **flp; - filter_def *filt; - - flp = get_filter_list(list); - filt = (filter_def *) g_malloc(sizeof(filter_def)); - filt->name = g_strdup(name); - filt->strval = g_strdup(expression); - *flp = g_list_append(*flp, filt); - return g_list_last(*flp); + GList **flpp; + + flpp = get_filter_list(list_type); + *flpp = add_filter_entry(*flpp, name, expression); + + return g_list_last(*flpp); } /* * Remove a filter from a list. */ void -remove_from_filter_list(filter_list_type_t list, GList *fl_entry) +remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry) { - GList **flp; - filter_def *filt; - - flp = get_filter_list(list); - filt = (filter_def *) fl_entry->data; - g_free(filt->name); - g_free(filt->strval); - g_free(filt); - *flp = g_list_remove_link(*flp, fl_entry); + GList **flpp; + + flpp = get_filter_list(list_type); + *flpp = remove_filter_entry(*flpp, fl_entry); } /* @@ -288,20 +460,20 @@ remove_from_filter_list(filter_list_type_t list, GList *fl_entry) * and "*errno_return" is set to the error. */ void -save_filter_list(filter_list_type_t list, char **pref_path_return, +save_filter_list(filter_list_type_t list_type, char **pref_path_return, int *errno_return) { - gchar *ff_path, *ff_path_new, *ff_dir = PF_DIR, *ff_name; - int path_length; + const gchar *ff_name; + gchar *ff_path, *ff_path_new; GList *fl; - GList *flp; + GList *flpp; filter_def *filt; FILE *ff; - struct stat s_buf; - + guchar *p, c; + *pref_path_return = NULL; /* assume no error */ - switch (list) { + switch (list_type) { case CFILTER_LIST: ff_name = CFILTER_FILE_NAME; @@ -318,64 +490,112 @@ save_filter_list(filter_list_type_t list, char **pref_path_return, return; } - path_length = strlen(get_home_dir()) + strlen(ff_dir) + strlen(ff_name) - + 4 + 4; - ff_path = (gchar *) g_malloc(path_length); - sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir); - - if (stat(ff_path, &s_buf) != 0) -#ifdef WIN32 - mkdir(ff_path); -#else - mkdir(ff_path, 0755); -#endif - - sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name); + ff_path = get_persconffile_path(ff_name, TRUE, TRUE); /* Write to "XXX.new", and rename if that succeeds. That means we don't trash the file if we fail to write it out completely. */ - ff_path_new = (gchar *) g_malloc(path_length); - sprintf(ff_path_new, "%s/%s/%s.new", get_home_dir(), ff_dir, ff_name); + ff_path_new = g_strdup_printf("%s.new", ff_path); - if ((ff = fopen(ff_path_new, "w")) == NULL) { + if ((ff = ws_fopen(ff_path_new, "w")) == NULL) { *pref_path_return = ff_path; *errno_return = errno; g_free(ff_path_new); return; } - flp = g_list_first(fl); - while (flp) { - filt = (filter_def *) flp->data; - fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval); + flpp = g_list_first(fl); + while (flpp) { + filt = (filter_def *) flpp->data; + + /* Write out the filter name as a quoted string; escape any quotes + or backslashes. */ + putc('"', ff); + for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) { + if (c == '"' || c == '\\') + putc('\\', ff); + putc(c, ff); + } + putc('"', ff); + + /* Separate the filter name and value with a space. */ + putc(' ', ff); + + /* Write out the filter expression and a newline. */ + fprintf(ff, "%s\n", filt->strval); if (ferror(ff)) { *pref_path_return = ff_path; *errno_return = errno; fclose(ff); - unlink(ff_path_new); + ws_unlink(ff_path_new); g_free(ff_path_new); return; } - flp = flp->next; + flpp = flpp->next; } if (fclose(ff) == EOF) { *pref_path_return = ff_path; *errno_return = errno; - unlink(ff_path_new); + ws_unlink(ff_path_new); g_free(ff_path_new); return; } - /* XXX - does "rename()" exist on Win32? If so, does it remove the - target first? If so, does that mean it's not atomic? */ - if (rename(ff_path_new, ff_path) < 0) { +#ifdef _WIN32 + /* ANSI C doesn't say whether "rename()" removes the target if it + exists; the Win32 call to rename files doesn't do so, which I + infer is the reason why the MSVC++ "rename()" doesn't do so. + We must therefore remove the target file first, on Windows. */ + if (ws_remove(ff_path) < 0 && errno != ENOENT) { + /* It failed for some reason other than "it's not there"; if + it's not there, we don't need to remove it, so we just + drive on. */ *pref_path_return = ff_path; *errno_return = errno; - unlink(ff_path_new); - g_free(ff_path); + ws_unlink(ff_path_new); + g_free(ff_path_new); + return; + } +#endif + + if (ws_rename(ff_path_new, ff_path) < 0) { + *pref_path_return = ff_path; + *errno_return = errno; + ws_unlink(ff_path_new); g_free(ff_path_new); return; } g_free(ff_path_new); g_free(ff_path); } + +/* + * Copy a filter list into another. + */ +void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type) +{ + GList **flpp_dest; + GList **flpp_src; + GList *flp_src; + filter_def *filt; + + g_assert(dest_type != src_type); + + flpp_dest = get_filter_list(dest_type); + flpp_src = get_filter_list(src_type); + flp_src = *flpp_src; + + /* throw away the "old" destination list - a NULL list is ok here */ + while(*flpp_dest) { + *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest)); + } + g_assert(g_list_length(*flpp_dest) == 0); + + /* copy the list entries */ + while(flp_src) { + filt = (filter_def *)(flp_src->data); + + *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval); + flp_src = g_list_next(flp_src); + } +} +