[PATCH 2/2] Bug-fixes and enhancements in utils: sanitization of exported names.
David Favro <[email protected]> Fri, 29 Oct 2010 13:25:11 -0400
| Newsgroups | gmane.comp.db.mdb-tools.devel |
|---|---|
| Message-ID | <[email protected]> |
* Moved sanitize_name() into its own header/source files, since the same function code had been implemented in two different source files (mdb-export.c and mdb-schema.c). * The enumerated type for specifying the column-data-type is now called MdbColDataType rather than the previous anonymous enum. * The open-file-failed error-messages in mdb-schema now contains the filename. Several error messages from mdb-export and mdb-schema now include the program-name. * mdb-export: boolean columns export as "true"/"false", rather than "0"/"1". * sanitize_names(): fixed bug: potential buffer-overflow-error. * sanitize_names(): looks for some SQL reserved words and if found attempts to mangle them to generate legal SQL. Signed-off-by: David Favro <[email protected]> --- AUTHORS | 3 ++ include/mdbtools.h | 4 +- src/util/Makefile.am | 3 ++ src/util/mdb-export.c | 35 ++++++--------------- src/util/mdb-schema.c | 36 +++++---------------- src/util/sanitize_name.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/sanitize_name.h | 29 +++++++++++++++++ 7 files changed, 134 insertions(+), 54 deletions(-) create mode 100644 src/util/sanitize_name.c create mode 100644 src/util/sanitize_name.h diff --git a/AUTHORS b/AUTHORS index f639990..e08069c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,3 +24,6 @@ David Mansfield <[email protected]> Jeff Smith <[email protected]> Patches too numerous to enumerate. + +David Favro <[email protected]> + Enhancements/fixes: sanitization of names for SQL. diff --git a/include/mdbtools.h b/include/mdbtools.h index 8e33df3..25fe793 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -74,7 +74,7 @@ enum { MDB_DATABASE_PROPERTY, MDB_ANY = -1 }; -enum { +typedef enum MdbColDataType { MDB_BOOL = 0x01, MDB_BYTE = 0x02, MDB_INT = 0x03, @@ -88,7 +88,7 @@ enum { MDB_MEMO = 0x0c, MDB_REPID = 0x0f, MDB_NUMERIC = 0x10 -}; +} MdbColDataType; /* SARG operators */ enum { diff --git a/src/util/Makefile.am b/src/util/Makefile.am index c872aec..8ecb716 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -7,3 +7,6 @@ LDADD = ../libmdb/libmdb.la if SQL mdb_sql_LDADD = ../libmdb/libmdb.la ../sql/libmdbsql.la $(LIBREADLINE) endif + +mdb_export_SOURCES = mdb-export.c sanitize_name.c sanitize_name.h +mdb_schema_SOURCES = mdb-schema.c sanitize_name.c sanitize_name.h diff --git a/src/util/mdb-export.c b/src/util/mdb-export.c index 8aa5290..e60e59a 100644 --- a/src/util/mdb-export.c +++ b/src/util/mdb-export.c @@ -23,16 +23,17 @@ #include "dmalloc.h" #endif +#include "sanitize_name.h" + #undef MDB_BIND_SIZE #define MDB_BIND_SIZE 200000 #define is_text_type(x) (x==MDB_TEXT || x==MDB_MEMO || x==MDB_SDATETIME) -static char *sanitize_name(char *str, int sanitize); static char *escapes(char *s); void -print_col(gchar *col_val, int quote_text, int col_type, char *quote_char, char *escape_char) +print_col(gchar *col_val, int quote_text, MdbColDataType col_type, char *quote_char, char *escape_char) { gchar *s; @@ -50,6 +51,8 @@ print_col(gchar *col_val, int quote_text, int col_type, char *quote_char, char * else fprintf(stdout,"%c",*s); } fprintf(stdout,quote_char); + } else if ( col_type == MDB_BOOL ) { + fputs( ((*col_val == '0') ? "false" : "true"), stdout ); } else { fprintf(stdout,"%s",col_val); } @@ -148,6 +151,7 @@ main(int argc, char **argv) g_free (quote_char); if (escape_char) g_free (escape_char); mdb_exit(); + fprintf( stderr, "%s: error opening \"%s\"\n", argv[0], argv[optind] ); exit(1); } @@ -174,11 +178,11 @@ main(int argc, char **argv) } if (header_row) { col=g_ptr_array_index(table->columns,0); - fprintf(stdout,"%s",sanitize_name(col->name,sanitize)); + fprintf(stdout,"%s",sanitize_name(col->name,sanitize,argv[0])); for (j=1;j<table->num_cols;j++) { col=g_ptr_array_index(table->columns,j); fprintf(stdout,delimiter); - fprintf(stdout,"%s",sanitize_name(col->name,sanitize)); + fprintf(stdout,"%s",sanitize_name(col->name,sanitize,argv[0])); } fprintf(stdout,"\n"); } @@ -187,11 +191,11 @@ main(int argc, char **argv) if (insert_statements) { fprintf(stdout, "INSERT INTO %s (", - sanitize_name(argv[optind + 1],sanitize)); + sanitize_name(argv[optind + 1],sanitize,argv[0])); for (j=0;j<table->num_cols;j++) { if (j>0) fprintf(stdout, ", "); col=g_ptr_array_index(table->columns,j); - fprintf(stdout,"%s", sanitize_name(col->name,sanitize)); + fprintf(stdout,"%s", sanitize_name(col->name,sanitize,argv[0])); } fprintf(stdout, ") VALUES ("); } @@ -231,25 +235,6 @@ main(int argc, char **argv) exit(0); } -static char *sanitize_name(char *str, int sanitize) -{ - static char namebuf[256]; - char *p = namebuf; - - if (!sanitize) - return str; - - while (*str) { - *p = isalnum(*str) ? *str : '_'; - p++; - str++; - } - - *p = 0; - - return namebuf; -} - static char *escapes(char *s) { char *d = (char *) g_strdup(s); diff --git a/src/util/mdb-schema.c b/src/util/mdb-schema.c index b142711..9216b20 100644 --- a/src/util/mdb-schema.c +++ b/src/util/mdb-schema.c @@ -24,8 +24,9 @@ #include "dmalloc.h" #endif -static char *sanitize_name(char *str, int sanitize); -static void generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize); +#include "sanitize_name.h" + +static void generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize, const char * prog_name); int main (int argc, char **argv) @@ -67,7 +68,7 @@ main (int argc, char **argv) /* open the database */ mdb = mdb_open (argv[optind], MDB_NOFLAGS); if (!mdb) { - fprintf(stderr, "Could not open file\n"); + fprintf(stderr, "%s: could not open file: \"%s\"\n", argv[0], argv[optind] ); mdb_exit(); exit(1); } @@ -101,7 +102,7 @@ main (int argc, char **argv) if (entry->object_type == MDB_TABLE) { if ((tabname && !strcmp(entry->object_name, tabname)) || (!tabname && mdb_is_user_table(entry))) { - generate_table_schema(entry, namespace, s); + generate_table_schema(entry, namespace, s, argv[0]); } } } @@ -122,7 +123,7 @@ main (int argc, char **argv) exit(0); } static void -generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) +generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize, const char * prog_name) { MdbTableDef *table; MdbHandle *mdb = entry->mdb; @@ -131,11 +132,11 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) /* drop the table if it exists */ fprintf (stdout, "DROP TABLE %s%s;\n", (namespace) ? namespace : "", - sanitize_name(entry->object_name, sanitize)); + sanitize_name(entry->object_name, sanitize, prog_name)); /* create the table */ fprintf (stdout, "CREATE TABLE %s%s\n", (namespace) ? namespace : "", - sanitize_name(entry->object_name, sanitize)); + sanitize_name(entry->object_name, sanitize, prog_name)); fprintf (stdout, " (\n"); table = mdb_read_table (entry); @@ -148,7 +149,7 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) for (i = 0; i < table->num_cols; i++) { col = g_ptr_array_index (table->columns, i); - fprintf (stdout, "\t%s\t\t\t%s", sanitize_name(col->name,sanitize), + fprintf (stdout, "\t%s\t\t\t%s", sanitize_name(col->name, sanitize, prog_name), mdb_get_coltype_string (mdb->default_backend, col->col_type)); if (mdb_coltype_takes_length(mdb->default_backend, @@ -173,22 +174,3 @@ generate_table_schema(MdbCatalogEntry *entry, char *namespace, int sanitize) mdb_free_tabledef (table); } - -static char *sanitize_name(char *str, int sanitize) -{ - static char namebuf[256]; - char *p = namebuf; - - if (!sanitize) - return str; - - while (*str) { - *p = isalnum(*str) ? *str : '_'; - p++; - str++; - } - - *p = 0; - - return namebuf; -} diff --git a/src/util/sanitize_name.c b/src/util/sanitize_name.c new file mode 100644 index 0000000..66d9640 --- /dev/null +++ b/src/util/sanitize_name.c @@ -0,0 +1,78 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * Portions copyright (C) 2008 David Favro + * + * 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 + */ + + +#include "sanitize_name.h" + +#include <stdio.h> /* fprintf(), stderr */ +#include <ctype.h> /* isalnum(), isdigit() */ +#include <stdlib.h> /* exit() */ + + +static const char * const RESERVED [] = + { + "CHECK" , + }; +#define N_RESERVED (sizeof(RESERVED)/sizeof(*RESERVED)) + + +char * sanitize_name(char *str, int sanitize, const char * prog_name) + { + static char namebuf[256]; + char *p = namebuf; + + if (!sanitize) + return str; + + const char * sPtr = str; + + if ( isdigit(*sPtr) ) + *p++ = '_'; + else + { + // Check for SQL keywords thay may be used as identifiers in Access. + // For the moment, just do a linear search through the keywords, with a + // string comparison for each. This probably should be replaced with a + // more sophisticated data structure such as a hash table. + + const char * const * rPtr; + for ( rPtr = RESERVED + N_RESERVED ; rPtr-- != RESERVED ; ) + if ( strcasecmp( str, *rPtr ) == 0 ) + { + *p++ = '_'; + break; // **** BREAK HERE **** + } + } + + char * const limit = namebuf + sizeof(namebuf); + + while (*sPtr) { + *p = isalnum(*sPtr) ? *sPtr : '_'; + if ( p++ >= limit ) { + fprintf( stderr, "%s: failed assertion: table-name buffer-overflow (%s)\n", + prog_name, str ); + exit( 1 ); + } + sPtr++; + } + + *p = '\0'; + + return namebuf; + } diff --git a/src/util/sanitize_name.h b/src/util/sanitize_name.h new file mode 100644 index 0000000..1fc9bcc --- /dev/null +++ b/src/util/sanitize_name.h @@ -0,0 +1,29 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * Portions copyright (C) 2008 David Favro + * + * 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 + */ + + + +#ifndef __sanitize_name_h +#define __sanitize_name_h + + +extern char * sanitize_name( char *str, int sanitize, const char * prog_name ); + + +#endif /* __sanitize_name_h */ -- 1.7.0.4 ------------------------------------------------------------------------------ Nokia and AT&T present the 2010 Calling All Innovators-North America contest Create new apps & games for the Nokia N8 for consumers in U.S. and Canada $10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store http://p.sf.net/sfu/nokia-dev2dev