diff options
403 files changed, 83497 insertions, 7730 deletions
diff --git a/.bzrignore b/.bzrignore index 5eb355adf90..4011bf5ff5e 100644 --- a/.bzrignore +++ b/.bzrignore @@ -20,6 +20,7 @@ .out .snprj/* .vimrc +=6 BitKeeper/etc/config BitKeeper/etc/csets BitKeeper/etc/csets-in @@ -179,6 +180,8 @@ include/my_config.h include/my_global.h include/mysql_version.h include/widec.h +innobase/conftest.s1 +innobase/conftest.subs innobase/ib_config.h innobase/ib_config.h.in isam/isamchk @@ -196,12 +199,94 @@ libmysql_r/acconfig.h libmysql_r/conf_to_src libmysql_r/my_static.h libmysql_r/mysys_priv.h +libmysqld/backup_dir +libmysqld/convert.cc +libmysqld/derror.cc +libmysqld/errmsg.c +libmysqld/field.cc +libmysqld/field_conv.cc +libmysqld/filesort.cc +libmysqld/get_password.c +libmysqld/ha_berkeley.cc +libmysqld/ha_heap.cc +libmysqld/ha_innobase.cc +libmysqld/ha_isam.cc +libmysqld/ha_isammrg.cc +libmysqld/ha_myisam.cc +libmysqld/ha_myisammrg.cc +libmysqld/handler.cc +libmysqld/hash_filo.cc +libmysqld/hostname.cc +libmysqld/init.cc +libmysqld/item.cc +libmysqld/item_buff.cc +libmysqld/item_cmpfunc.cc +libmysqld/item_create.cc +libmysqld/item_func.cc +libmysqld/item_strfunc.cc +libmysqld/item_sum.cc +libmysqld/item_timefunc.cc +libmysqld/item_uniq.cc +libmysqld/key.cc +libmysqld/lock.cc +libmysqld/log.cc +libmysqld/log_event.cc +libmysqld/md5.c +libmysqld/mini_client.cc +libmysqld/net_pkg.cc +libmysqld/net_serv.cc +libmysqld/opt_ft.cc +libmysqld/opt_range.cc +libmysqld/opt_sum.cc +libmysqld/password.c +libmysqld/procedure.cc +libmysqld/records.cc +libmysqld/simple-test +libmysqld/slave.cc +libmysqld/sql_acl.cc +libmysqld/sql_analyse.cc +libmysqld/sql_base.cc +libmysqld/sql_cache.cc +libmysqld/sql_class.cc +libmysqld/sql_command +libmysqld/sql_crypt.cc +libmysqld/sql_db.cc +libmysqld/sql_delete.cc +libmysqld/sql_handler.cc +libmysqld/sql_insert.cc +libmysqld/sql_lex.cc +libmysqld/sql_list.cc +libmysqld/sql_load.cc +libmysqld/sql_manager.cc +libmysqld/sql_map.cc +libmysqld/sql_parse.cc +libmysqld/sql_rename.cc +libmysqld/sql_repl.cc +libmysqld/sql_select.cc +libmysqld/sql_show.cc +libmysqld/sql_string.cc +libmysqld/sql_table.cc +libmysqld/sql_test.cc +libmysqld/sql_udf.cc +libmysqld/sql_union.cc +libmysqld/sql_unions.cc +libmysqld/sql_update.cc +libmysqld/sql_yacc.cc +libmysqld/stacktrace.c +libmysqld/table.cc +libmysqld/thr_malloc.cc +libmysqld/time.cc +libmysqld/uniques.cc +libmysqld/unireg.cc libtool linked_client_sources linked_include_sources linked_libmysql_r_sources linked_libmysql_sources +linked_libmysqld_sources linked_server_sources +linked_tools_sources +locked myisam/ft_dump myisam/ft_eval myisam/ft_test1 @@ -218,6 +303,7 @@ mysql-test/gmon.out mysql-test/install_test_db mysql-test/mysql-test-run mysql-test/r/*.reject +mysql-test/r/rpl_log.eval mysql-test/share/mysql mysql-test/var/* mysql.kdevprj @@ -247,10 +333,12 @@ scripts/mysql_zap scripts/mysqlaccess scripts/mysqlbug scripts/mysqld_multi +scripts/mysqld_safe scripts/mysqldumpslow scripts/mysqlhotcopy scripts/safe_mysqld sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686 +sql-bench/bench-count-distinct sql-bench/bench-init.pl sql-bench/compare-results sql-bench/compare-results-all @@ -280,8 +368,10 @@ sql/mysqld sql/share/*.sys sql/share/charsets/gmon.out sql/share/gmon.out +sql/share/mysql sql/share/norwegian-ny/errmsg.sys sql/share/norwegian/errmsg.sys +sql/sql_select.cc.orig sql/sql_yacc.cc sql/sql_yacc.h stamp-h @@ -303,3 +393,10 @@ support-files/mysql.server support-files/mysql.spec tags tmp/* +tools/my_vsnprintf.c +tools/mysqlmngd +tools/mysys_priv.h +vio/test-sslclient +vio/test-sslserver +vio/viotest-ssl +tools/mysqlmanager diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 778625e9e75..fdd0154fc99 100644 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -40,7 +40,7 @@ c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wextern-inline -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" alpha_cflags="-mcpu=ev6 -Wa,-mev6" # Not used yet -pentium_cflags="-mpentiumpro" +pentium_cflags="" sparc_cflags="" # be as fast as we can be without losing our ability to backtrace @@ -52,7 +52,8 @@ debug_cflags="-DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DSAFE_MUTEX -O2" base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" -base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static" +base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static \ + --with-client-ldflags=-all-static" alpha_configs="" # Not used yet pentium_configs="" sparc_configs="" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index dc88bab62d3..4149267811d 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -8,6 +8,6 @@ c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs" -extra_configs="$extra_configs --with-berkeley-db --with-innodb" +extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-embedded-server" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-debug-openssl b/BUILD/compile-pentium-debug-openssl new file mode 100755 index 00000000000..aa120e3175a --- /dev/null +++ b/BUILD/compile-pentium-debug-openssl @@ -0,0 +1,13 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs" + +extra_configs="$extra_configs --with-debug=full --with-vio --with-openssl" + +. "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-mysqlfs-debug b/BUILD/compile-pentium-mysqlfs-debug new file mode 100755 index 00000000000..2455c086532 --- /dev/null +++ b/BUILD/compile-pentium-mysqlfs-debug @@ -0,0 +1,13 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs" + +extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server --without-pstack" + +. "$path/FINISH.sh" diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 390c414d29c..81a2ba694f7 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -1,21 +1,30 @@ +Sinisa@sinisa.nasamreza.org davida@isil.mysql.com heikki@donna.mysql.fi jani@hynda.mysql.fi jani@janikt.pp.saunalahti.fi +jcole@abel.spaceapes.com +jcole@main.burghcom.com jcole@tetra.spaceapes.com miguel@light.local monty@bitch.mysql.fi +monty@donna.mysql.fi monty@hundin.mysql.fi monty@tik.mysql.fi monty@work.mysql.com mwagner@evoq.mwagner.org paul@central.snake.net paul@teton.kitebird.com +root@x3.internalnet sasha@mysql.sashanet.com serg@serg.mysql.com +tfr@sarvik.tfr.cafe.ee tim@bitch.mysql.fi +tim@black.box +tim@hundin.mysql.fi tim@threads.polyesthetic.msg tim@white.box tim@work.mysql.com +tonu@hundin.mysql.fi tonu@x153.internalnet -tfr@sarvik.tfr.cafe.ee +tonu@x3.internalnet diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index dc5f2f2b824..895c813c9e6 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -23,7 +23,7 @@ then List-ID: <bk.mysql> From: $FROM To: $TO -Subject: bk commit into 3.23 tree +Subject: bk commit - 4.0 tree EOF bk changes -v -r+ @@ -35,14 +35,13 @@ EOF List-ID: <bk.mysql> From: $FROM To: $INTERNALS -Subject: bk commit into 3.23 tree +Subject: bk commit into 4.0 tree -Below is the list of changes that have just been commited into a local -3.23. repository of $USER. When $USER does a push, they will be -propogaged to the main repository and within 24 hours after the push into -the public repository. For information on how to access -the public repository see -http://www.mysql.com/doc/I/n/Installing_source_tree.html +Below is the list of changes that have just been committed into a +4.0 repository of $USER. When $USER does a push, they will be propogated to +the main repository and within 24 hours after the push to the public repository. +For information on how to access the public repository +see http://www.mysql.com/doc/I/n/Installing_source_tree.html EOF bk changes -v -r+ diff --git a/Docs/manual.texi b/Docs/manual.texi index a61faa7647e..2a2560c003f 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -145,14 +145,14 @@ distribution for that version. @cindex online location of manual @cindex manual, online location -This is the MySQL reference manual; it documents MySQL -Version @value{mysql_version}. As MySQL is work in progress, -the manual gets updated frequently. There is a very good chance that -this version is out of date, unless you are looking at it online. The -most recent version of this manual is available at -@uref{http://www.mysql.com/documentation/} in many different formats. If you -have a hard time finding information in the manual, you can try the -searchable PHP version at @uref{http://www.mysql.com/documentation/manual.php}. +This is the MySQL reference manual; it documents MySQL Version +@value{mysql_version}. As MySQL is work in progress, the manual gets +updated frequently. There is a very good chance that this version is +out of date, unless you are looking at it online. The most recent +version of this manual is available at +@uref{http://www.mysql.com/documentation/index.html} in many different +formats. If you have a hard time finding information in the manual, you +can try the searchable PHP version at @uref{http://www.mysql.com/doc}. MySQL is a very fast, multi-threaded, multi-user, and robust SQL (Structured Query Language) database server. @@ -182,6 +182,10 @@ For tips on porting MySQL to new architectures or operating systems, see @ref{Porting}. @item +For information about upgrading from a Version 3.23 release, see +@ref{Upgrading-from-3.23}. + +@item For information about upgrading from a Version 3.22 release, see @ref{Upgrading-from-3.22}. @@ -744,7 +748,7 @@ is also available through the SQL interface as well. @item Full support for several different character sets, including -ISO-8859-1 (Latin1), big5, ujis, and more. For example, the +ISO-8859-1 (Latin1), german, big5, ujis, and more. For example, the Scandinavian characters `@ringaccent{a}', `@"a' and `@"o' are allowed in table and column names. @@ -1484,36 +1488,19 @@ A complete reference to DBI. @node General-SQL, Useful Links, MySQL-Books, MySQL Information Sources @subsection General SQL Information and Tutorials -The following book has been recommended by several people on the MySQL -mailing list: - -@example -Judith S. Bowman, Sandra L. Emerson and Marcy Darnovsky -@emph{The Practical SQL Handbook: Using Structured Query Language} -Second Edition -Addison-Wesley -ISBN 0-201-62623-3 -http://www.awl.com -@end example - -The following book has also received some recommendations by MySQL -users: - -@example -Martin Gruber -@emph{Understanding SQL} -ISBN 0-89588-644-8 -Publisher Sybex 510 523 8233 -Alameda, CA USA -@end example - -A SQL tutorial is available on the net at -http://w3.one.net/~jhoffman/sqltut.htm +The MySQL book portal is split into different sections to make it easy +to locate books for various purposes. +@uref{http://www.mysql.com/portal/books/html/index.html} +Tutorials can be found at: +@uref{http://www.mysql.com/portal/development/html/development-61-1.html} @node Useful Links, Questions, General-SQL, MySQL Information Sources @subsection Useful MySQL-related Links +The MySQL development portal is the ultimate source of MySQL related +links. @uref{http://www.mysql.com/portal/development/html/index.html} + Apart from the following links, you can find and download a lot of MySQL programs, tools and APIs from the @uref{http://www.mysql.com/Downloads/Contrib/, Contrib directory}. @@ -5348,10 +5335,11 @@ SQL functions and aggregates, but this is not yet as easy or as flexible as in PostgreSQL. @xref{Adding functions}. @item -Updates and deletes that run over multiple tables is harder to do in -MySQL. This will, hoever, be fixed in MySQL 4.0 with multi-table -@code{DELETE} and multi-table @code{UPDATE} and in MySQL 4.1 -with subselects. +Updates that run over multiple tables is harder to do in MySQL. +This will, however, be fixed in MySQL 4.0 with multi-table @code{UPDATE} +and in MySQL 4.1 with subselects. +In MySQL 4.0 one can use multi-table deletes to delete from many tables +at the same time. @xref{DELETE}. @end itemize PostgreSQL currently offers the following advantages over MySQL: @@ -5724,6 +5712,9 @@ master. @code{DELETE FROM table_name} will return the number of deleted rows. For fast execution one should use @code{TRUNCATE table_name}. @item +Multi-table @code{DELETE} (cascading @code{DELETE} and multi-table +@code{DELETE}. +@item Allow @code{DELETE} on @code{MyISAM} tables to use the record cache. To do this, we need to update the threads record cache when we update the @code{.MYD} file. @@ -5820,6 +5811,8 @@ Multiple result sets. Change the protocol to allow binary transfer of values. To do this efficiently, we need to add an API to allow binding of variables. @item +Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}. +@item Make it possible to specify @code{long_query_time} with a granularity in microseconds. @item @@ -6394,10 +6387,10 @@ information about the current version and for downloading instructions. Our main download mirror is located at: -@uref{http://download.sourceforge.net/mirrors/mysql/} +@uref{http://mirrors.sunsite.dk/mysql/} If you are interested in becoming a MySQL mirror site, you may -anonymously rsync with: @code{rsync://download.sourceforge.net/mysql/}. Please +anonymously rsync with: @code{rsync://sunsite.dk/ftp/mirrors/mysql/}. Please send e-mail to @email{webmaster@@mysql.com} notifying us of your mirror to be added to the list below. @@ -6467,7 +6460,7 @@ Please report bad or out-of-date mirrors to @email{webmaster@@mysql.com}. @uref{ http://mysql.borsen.dk/, WWW} @item -@c EMAIL: mkp@socsci.auc.dk (Martin Kasper Petersen) +@c EMAIL: mirror@sunsite.dk (Mirror Admin Team) @image{Flags/denmark} Denmark [SunSITE] @ @uref{http://mirrors.sunsite.dk/mysql/, WWW} @uref{ftp://sunsite.dk/mirrors/mysql/, FTP} @@ -9312,14 +9305,45 @@ particularly if you notice symptoms such as all your @code{DBI} scripts dumping core after you upgrade MySQL. @menu +* Upgrading-from-3.23:: Upgrading from a 3.23 version to 4.0 * Upgrading-from-3.22:: Upgrading from a 3.22 version to 3.23 * Upgrading-from-3.21:: Upgrading from a 3.21 version to 3.22 * Upgrading-from-3.20:: Upgrading from a 3.20 version to 3.21 * Upgrading-to-arch:: Upgrading to another architecture @end menu +@cindex compatibility, between MySQL versions +@cindex upgrading, 3.23 to 4.0 +@node Upgrading-from-3.23, Upgrading-from-3.22, Upgrade, Upgrade +@subsection Upgrading From Version 3.23 to Version 4.0 + +You can use your old data files without any modification with Version 4.0. +If you want to move your data from a MySQL 4.0 server to an older server, +you have to use @code{mysqldump}. + +Old clients should work with a Version 4.0 server without any problems. + +The following lists tell what you have to watch out for when upgrading to +Version 4.0; + +@itemize @bullet +@item +@file{safe_mysqld} is renamed to @file{mysqld_safe}. +@item +The old C API functions @code{mysql_drop_db}, @code{mysql_create_db} and +@code{mysql_connect} are not supported anymore, unless one compiles +MySQL with @code{USE_OLD_FUNCTIONS}. +@item +You should use @code{TRUNCATE TABLE} when you want to delete all rows +from a table and you don't care of how many rows where deleted. +(Because @code{TRUNCATE TABLE} is faster than @code{DELETE FROM table_name}). +@item +You will get an error if you have an active @code{LOCK TABLES} or +transaction when trying to execute @code{TRUNCATE TABLE} or @code{DROP +DATABASE}. +@end itemize -@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrade, Upgrade +@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrading-from-3.23, Upgrade @subsection Upgrading From Version 3.22 to Version 3.23 @cindex compatibility, between MySQL versions @@ -16929,6 +16953,7 @@ GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...] ON @{tbl_name | * | *.* | db_name.*@} TO user_name [IDENTIFIED BY 'password'] [, user_name [IDENTIFIED BY 'password'] ...] + [REQUIRE @{SSL|X509@} [ISSUER issuer] [SUBJECT subject]] [WITH GRANT OPTION] REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...] @@ -20438,6 +20463,35 @@ default-character-set=character-set-name but normally this is never needed. +@menu +* German character set:: +@end menu + +@node German character set, , Character sets, Character sets +@subsubsection German character set + +To get German sorting order, you should start @code{mysqld} with +@code{--default-character-set=latin_de}. This will give you the following +characteristics. + +When sorting and comparing string's the following mapping is done on the +strings before doing the comparison: + +@example +ä -> ae +ö -> oe +ü -> ue +ß -> ss +@end example + +All accented characters, except @code{'é'} and @code{É} are converted to +their un-accented counterpart. All letters are converted to uppercase. + +When comparing strings with @code{LIKE} the one -> two character mapping +is not done. All letters are converted to uppercase. Accent are removed +from all letters except: @code{Ü}, @code{ü}, @code{É}, @code{é}, @code{Ö}, +@code{ö}, @code{Ä} and @code{ä}. + @node Languages, Adding character set, Character sets, Localization @subsection Non-English Error Messages @@ -23683,10 +23737,25 @@ Example: @code{master-port=3306}. @item @code{master-connect-retry=seconds} @tab The number of seconds the slave thread will sleep before retrying to connect to the master in case the master goes down or the connection is -lost. Default is 60. +lost. Default is 60. Example: @code{master-connect-retry=60}. +@item @code{master-ssl} @tab +Turn SSL on + +Example: @code{master-ssl}. + +@item @code{master-ssl-key} @tab +Master SSL keyfile name + +Example: @code{master-ssl-key=SSL/master-key.pem}. + +@item @code{master-ssl-cert} @tab +Master SSL certificate file name + +Example: @code{master-ssl-key=SSL/master-cert.pem}. + @item @code{master-info-file=filename} @tab The location of the file that remembers where we left off on the master during the replication process. The default is master.info in the data @@ -25395,6 +25464,8 @@ Some ways to speed up inserts: If you are inserting many rows from the same client at the same time, use multiple value lists @code{INSERT} statements. This is much faster (many times in some cases) than using separate @code{INSERT} statements. +Tune up @code{myisam_bulk_insert_tree_size} variable to make it even +faster. @xref{SHOW VARIABLES}. @item If you are inserting a lot of rows from different clients, you can get higher speed by using the @code{INSERT DELAYED} statement. @xref{INSERT, @@ -25444,6 +25515,13 @@ flush-tables}. This procedure will be built into @code{LOAD DATA INFILE} in some future version of MySQL. + +Since @strong{MySQL 4.0} you can also use +@code{ALTER TABLE tbl_name DISABLE KEYS} instead of +@code{myisamchk --keys-used=0 -rq /path/to/db/tbl_name} and +@code{ALTER TABLE tbl_name ENABLE KEYS} instead of +@code{myisamchk -r -q /path/to/db/tbl_name}. This way you can also skip +@code{FLUSH TABLES} steps. @item You can speed up insertions by locking your tables: @@ -27244,8 +27322,6 @@ Things that are not yet supported: @end itemize - - @node Reference, Table types, MySQL Optimization, Top @chapter MySQL Language Reference @@ -27257,6 +27333,7 @@ Things that are not yet supported: * Data Definition:: Data Definition: @code{CREATE}, @code{DROP}, @code{ALTER} * Basic User Commands:: Basic MySQL User Utility Commands * Transactional Commands:: MySQL Transactional and Locking Commands +* HANDLER:: * Fulltext Search:: MySQL Full-text Search @end menu @@ -27505,12 +27582,16 @@ like an integer (64-bit precision). In string context these act like a binary string where each pair of hex digits is converted to a character: @example +mysql> SELECT x'FF' + -> 255 mysql> SELECT 0xa+0; -> 10 mysql> select 0x5061756c; -> Paul @end example +The x'hexstring' syntax (new in 4.0) is based on ANSI SQL and the 0x +syntax is based on ODBC. Hexadecimal strings are often used by ODBC to give values for BLOB columns. @@ -32046,6 +32127,7 @@ facilitate replication testing. @menu * SELECT:: @code{SELECT} Syntax +* UNION:: * INSERT:: @code{INSERT} Syntax * INSERT DELAYED:: @code{INSERT DELAYED} syntax * UPDATE:: @code{UPDATE} Syntax @@ -32055,7 +32137,7 @@ facilitate replication testing. * LOAD DATA:: @code{LOAD DATA INFILE} Syntax @end menu -@node SELECT, INSERT, Data Manipulation, Data Manipulation +@node SELECT, UNION, Data Manipulation, Data Manipulation @subsection @code{SELECT} Syntax @findex SELECT @@ -32483,7 +32565,40 @@ mysql> select * from table1 IGNORE INDEX (key3) WHERE key1=1 and key2=2 AND @xref{LEFT JOIN optimization, , @code{LEFT JOIN} optimization}. -@node INSERT, INSERT DELAYED, SELECT, Data Manipulation +@node UNION, INSERT, SELECT, Data Manipulation +@subsection @code{UNION} Syntax + +@findex UNION + +@example +SELECT .... +UNION [ALL] +SELECT .... + [UNION + SELECT ...] +@end example + +@code{UNION} is implemented in MySQL 4.0.0. + +@code{UNION} is used to combine the result from many @code{SELECT} +statements into one result set. + +The @code{SELECT} commands are normal select commands, but with the following +restrictions: + +@itemize @bullet +@item +Only the last @code{SELECT} command can have @code{INTO OUTFILE}. +@item +Only the last @code{SELECT} command can have @code{ORDER BY}. +@end itemize + +If you don't use the keyword @code{ALL} for the @code{UNION}, all +returned rows will be unique, like if you had done a @code{DISTINCT} for +the total result set. If you specify @code{ALL}, then you will get all +matching rows from all the used @code{SELECT} statements. + +@node INSERT, INSERT DELAYED, UNION, Data Manipulation @subsection @code{INSERT} Syntax @findex INSERT @@ -32855,40 +32970,82 @@ only a given number of rows are changed. @findex DELETE @example -DELETE [LOW_PRIORITY] FROM tbl_name +DELETE [LOW_PRIORITY | QUICK] FROM table_name [WHERE where_definition] + [ORDER BY ...] [LIMIT rows] + +or + +DELETE [LOW_PRIORITY | QUICK] table_name[.*] [table_name[.*] ...] FROM +table-references [WHERE where_definition] @end example -@code{DELETE} deletes rows from @code{tbl_name} that satisfy the condition +@code{DELETE} deletes rows from @code{table_name} that satisfy the condition given by @code{where_definition}, and returns the number of records deleted. If you issue a @code{DELETE} with no @code{WHERE} clause, all rows are deleted. If you do this in @code{AUTOCOMMIT} mode, this works as -@code{TRUNCATE}. @xref{TRUNCATE}. One problem with this is that -@code{DELETE} will return zero as the number of affected records, but -this will be fixed in 4.0. +@code{TRUNCATE}. @xref{TRUNCATE}. In MySQL 3.23 @code{DELETE} without a +@code{WHERE} clause will return zero as the number of affected records. If you really want to know how many records are deleted when you are deleting all rows, and are willing to suffer a speed penalty, you can use a @code{DELETE} statement of this form: @example -mysql> DELETE FROM tbl_name WHERE 1>0; +mysql> DELETE FROM table_name WHERE 1>0; @end example -Note that this is MUCH slower than @code{DELETE FROM tbl_name} with no +Note that this is MUCH slower than @code{DELETE FROM table_name} with no @code{WHERE} clause, because it deletes rows one at a time. If you specify the keyword @code{LOW_PRIORITY}, execution of the @code{DELETE} is delayed until no other clients are reading from the table. -Deleted records are maintained in a linked list and subsequent @code{INSERT} -operations reuse old record positions. To reclaim unused space and reduce -file sizes, use the @code{OPTIMIZE TABLE} statement or the @code{myisamchk} -utility to reorganize tables. @code{OPTIMIZE TABLE} is easier, but -@code{myisamchk} is faster. -See @ref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}} and @ref{Optimization}. +If you specify the word @code{QUICK} then the table handler will not +merge index leafs during delete, which may speed up certain kind of +deletes. + +In MyISAM tables deleted records are maintained in a linked list and +subsequent @code{INSERT} operations reuse old record positions. To +reclaim unused space and reduce file sizes, use the @code{OPTIMIZE +TABLE} statement or the @code{myisamchk} utility to reorganize tables. +@code{OPTIMIZE TABLE} is easier, but @code{myisamchk} is faster. See +@ref{OPTIMIZE TABLE, , @code{OPTIMIZE TABLE}} and @ref{Optimization}. + +The multi table delete format is supported starting from MySQL 4.0.0. + +The idea is that only matching rows from the tables listed BEFORE the +@code{FROM} clause is deleted. The effect is that you can delete rows +from many tables at the same time and also have additional tables that +are used for searching. + +The @code{.*} after the table names is there just to be compatible with +@code{Access}: + +@example +DELETE t1,t2 FROM t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id +@end example + +In the above case we delete matching rows just from tables @code{t1} and +@code{t2}. + +@code{ORDER BY} and using multiple tables in the DELETE is supported in +MySQL 4.0. + +If an @code{ORDER BY} clause is used, the rows will be deleted in that order. +This is really only useful in conjunction with @code{LIMIT}. For example: + +@example +DELETE FROM somelog +WHERE user = 'jcole' +ORDER BY timestamp +LIMIT 1 +@end example + +This will delete the oldest entry (by @code{timestamp}) where the row matches +the @code{WHERE} clause. The MySQL-specific @code{LIMIT rows} option to @code{DELETE} tells the server the maximum number of rows to be deleted before control is @@ -32907,16 +33064,19 @@ the @code{LIMIT} value. TRUNCATE TABLE table_name @end example -Is in 3.23 and the same thing as @code{DELETE FROM table_name}. @xref{DELETE}. -The differences are: +In 3.23 @code{TRUNCATE TABLE} is mapped to +@code{COMMIT ; DELETE FROM table_name}. @xref{DELETE}. + +The differences between @code{TRUNCATE TABLE} and @code{DELETE FROM ..} +are: @itemize @bullet @item -Implemented as a drop and re-create of the table, which makes this -much faster when deleting many rows. +Truncates does a drop and re-create of the table, which is much faster +than deleting rows one by one. @item -Not transaction-safe; @code{TRUNCATE TABLE} will automatically end the current -transaction as if @code{COMMIT} would have been called. +Not transaction-safe; You will get an error if you have an active +transaction or an active table lock. @item Doesn't return the number of deleted rows. @item @@ -32927,7 +33087,6 @@ files have become corrupted. @code{TRUNCATE} is an Oracle SQL extension. - @node REPLACE, LOAD DATA, TRUNCATE, Data Manipulation @subsection @code{REPLACE} Syntax @@ -34079,6 +34238,8 @@ alter_specification: or DROP [COLUMN] col_name or DROP PRIMARY KEY or DROP INDEX index_name + or DISABLE KEYS + or ENABLE KEYS or RENAME [TO] new_tbl_name or ORDER BY col or table_options @@ -34147,6 +34308,15 @@ options, MySQL simply renames the files that correspond to the table @xref{RENAME TABLE,, @code{RENAME TABLE}}. @item +Since @strong{MySQL 4.0} the above feature can be activated explicitly. +@code{ALTER TABLE ... DISABLE KEYS} makes MySQL to stop updating +non-unique indexes for @code{MyISAM} table. +@code{ALTER TABLE ... ENABLE KEYS} then should be used to recreate missing +indexes. As MySQL does it with special algorithm which is much +faster then inserting keys one by one, disabling keys could give a +considerable speedup on bulk inserts. + +@item @code{create_definition} clauses use the same syntax for @code{ADD} and @code{CHANGE} as for @code{CREATE TABLE}. Note that this syntax includes the column name, not just the column type. @@ -34246,6 +34416,15 @@ indexes are created in a separate batch (like in @code{REPAIR}). This should make @code{ALTER TABLE} much faster when you have many indexes. @item +Since @strong{MySQL 4.0} this can be activated explicitly. +@code{ALTER TABLE ... DISABLE KEYS} makes MySQL to stop updating +non-unique indexes for @code{MyISAM} table. +@code{ALTER TABLE ... ENABLE KEYS} then should be used to recreate missing +indexes. As MySQL does it with special algorithm which is much +faster then inserting keys one by one, disabling keys could give a +considerable speedup on bulk inserts. + +@item @findex mysql_info() With the C API function @code{mysql_info()}, you can find out how many records were copied, and (when @code{IGNORE} is used) how many records were @@ -34541,7 +34720,7 @@ The @code{SHOW} statement provides similar information. @xref{SHOW, , @code{SHOW}}. -@node Transactional Commands, Fulltext Search, Basic User Commands, Reference +@node Transactional Commands, HANDLER, Basic User Commands, Reference @section MySQL Transactional and Locking Commands @menu @@ -34774,8 +34953,48 @@ future transactions. You can set the default isolation level for @code{mysqld} with @code{--transaction-isolation=...}. @xref{Command-line options}. +@findex HANDLER +@node HANDLER, Fulltext Search, Transactional Commands, Reference +@section @code{HANDLER} Syntax + +@example +HANDLER table OPEN [ AS alias ] +HANDLER table READ index @{ = | >= | <= | < @} (value1, value2, ... ) [ WHERE ... ] [LIMIT ... ] +HANDLER table READ index @{ FIRST | NEXT | PREV | LAST @} [ WHERE ... ] [LIMIT ... ] +HANDLER table READ @{ FIRST | NEXT @} [ WHERE ... ] [LIMIT ... ] +HANDLER table CLOSE +@end example + +The @code{HANDLER} statement provides direct access to MySQL table +interface, bypassing SQL optimizer. Thus, it is faster then SELECT. + +The first form of @code{HANDLER} statement opens a table, making +in accessible via the following @code{HANDLER ... READ} routines. + +The second form fetches one (or, specified by @code{LIMIT} clause) row +where the index specified complies to the condition and @code{WHERE} +condition is met. If the index consists of several parts (spans over +several columns) the values are specified in comma-separated list, +providing values only for few first columns is possible. + +The third form fetches one (or, specified by @code{LIMIT} clause) row +from the table in index order, matching @code{WHERE} condition. + +The fourth form (without index specification) fetches one (or, specified +by @code{LIMIT} clause) row from the table in natural row order (as stored +in data file) matching @code{WHERE} condition. It is faster than +@code{HANDLER table READ index} when full table scan is desired. + +The last form closes the table, opened with @code{HANDLER ... OPEN}. -@node Fulltext Search, , Transactional Commands, Reference +@code{HANDLER} is somewhat low-level statement, for example it does not +provide consistency. That is @code{HANDLER ... OPEN} does @strong{not} +takes a snapshot of the table, and does @strong{not} locks the table. The +above means, that after @code{HANDLER ... OPEN} table data can be +modified (by this or other thread) and these modifications may appear only +partially in @code{HANDLER ... NEXT} or @code{HANDLER ... PREV} scans. + +@node Fulltext Search, , HANDLER, Reference @section MySQL Full-text Search @cindex searching, full-text @@ -35035,8 +35254,6 @@ parameters to @code{FULLTEXT} in @code{CREATE/ALTER TABLE}). @end itemize - - @node Table types, Clients, Reference, Top @chapter MySQL Table Types @@ -37115,9 +37332,8 @@ InnoDB database. @strong{9.} Beware also of other big disk-bound operations. -Use @code{DROP TABLE} -or @code{TRUNCATE} (from MySQL-4.0 up) to empty a table, not -@code{DELETE FROM yourtable}. +Use @code{DROP TABLE} or @code{TRUNCATE} (from MySQL-4.0 up) to empty a +table, not @code{DELETE FROM yourtable}. @strong{10.} Use the multi-line @code{INSERT} to reduce @@ -46699,8 +46915,9 @@ this means that the version has not yet been released! @node News-4.0.x, News-3.23.x, News, News @appendixsec Changes in release 4.0.x (Development; Alpha) -We have now started to work on MySQL 4.0. We will update this -section as we add new features, so that others can follow our development. +We are now working actively on MySQL 4.0 and will only provide critical +bug fixes for MySQL 3.23. We will update this section as we add new +features, so that others can follow our development. Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. @@ -46716,32 +46933,53 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. @itemize @bullet @item -Multi-table @code{DELETE}. +New character set @code{latin_de} which provides correct German sorting. +@item +@code{TRUNCATE TABLE} and @code{DELETE FROM table_name} are now separate +functions. One bonus is that @code{DELETE FROM table_name} now returns +the number of deleted rows. +@item +@code{DROP DATABASE} now executes a @code{DROP TABLE} on all tables in +the database, which fixes a problem with InnoDB tables. +@item +Changed @code{WEEK(#,0)} to match the calender in the USA. +@item +Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK} @item -Don't support old client protocols prior to MySQL 3.21 any more. +Fixed problem with @code{DATETIME = constant} in @code{WHERE} optimization. @item -Don't include the old C API functions @code{mysql_drop_db}, -@code{mysql_create_db} and @code{mysql_connect}, unless compiled with -@code{USE_OLD_FUNCTIONS}. +Speed up all internal list handling. +@item +Added support for @code{UNION}. +@item +Allow ANSI SQL syntax @code{X'hexadecimal-number'} +@item +Tree-like cache to speed up bulk inserts and +@code{myisam_bulk_insert_tree_size} variable. +@item +Added @code{ALTER TABLE table_name DISABLE KEYS} and +@code{ALTER TABLE table_name ENABLE KEYS} commands. +@item +@code{LOAD DATA FROM MASTER} "auto-magically" sets up a slave. @item Renamed @code{safe_mysqld} to @code{mysqld_safe}. @item -Allow @code{IN} as a synonym for @code{FROM} in @code{SHOW} commands. +Allow one to use @code{IN} instead of @code{FROM} in @code{SHOW} commands. @item @code{SHOW INDEXES} is now a synonym for @code{SHOW INDEX}. @item Added support for symbolic links to @code{MyISAM} tables. Symlink handling is now enabled by default for Windows. @item -@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave. +@code{LOAD DATA FROM MASTER} "auto-magically" sets up a slave. @item A new @code{HANDLER} interface to @code{MyISAM} tables. @item @code{COUNT(DISTINCT)} is about 30% faster. @item -@code{FULLTEXT} index creation now is much faster. +Creating full text indexes are now much faster. @item -Searching on packed (@code{CHAR}/@code{VARCHAR}) keys now is much faster. +Searching on packed (@code{CHAR}/@code{VARCHAR}) keys are now much faster. @item Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it possible to know how many rows a query would have returned @@ -52716,8 +52954,8 @@ update statements if you want to narrow down the problem. @cindex clients, debugging To be able to debug a MySQL client with the integrated debug package, -you should configure MySQL with @code{--with-debug}. -@xref{configure options}. +you should configure MySQL with @code{--with-debug} or +@code{--with-debug=full}. @xref{configure options}. @tindex MYSQL_DEBUG environment variable @tindex Environment variable, MYSQL_DEBUG diff --git a/Makefile.am b/Makefile.am index 22e066ac9d4..61ea903ddb2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,15 +22,19 @@ TAR = gtar EXTRA_DIST = INSTALL-SOURCE README \ COPYING COPYING.LIB MIRRORS SUBDIRS = include @docs_dirs@ @readline_dir@ \ - @thread_dirs@ @sql_client_dirs@ \ - @sql_server_dirs@ scripts tests man \ - @bench_dirs@ support-files + @thread_dirs@ @pstack_dirs@ @sql_client_dirs@ \ + @sql_server_dirs@ @libmysqld_dirs@ scripts tests man \ + @bench_dirs@ support-files @fs_dirs@ @tools_dirs@ # Relink after clean -CLEANFILES = linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources linked_include_sources +linked_sources = linked_client_sources linked_server_sources \ + linked_libmysql_sources linked_libmysql_r_sources \ + linked_libmysqld_sources linked_include_sources + +CLEANFILES = $(linked_sources) # This is just so that the linking is done early. -config.h: linked_include_sources linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources +config.h: $(linked_sources) linked_include_sources: cd include; $(MAKE) link_sources @@ -48,6 +52,10 @@ linked_libmysql_r_sources: linked_libmysql_sources cd libmysql_r; $(MAKE) link_sources echo timestamp > linked_libmysql_r_sources +linked_libmysqld_sources: + cd libmysqld; $(MAKE) link_sources + echo timestamp > linked_libmysqld_sources + #avoid recursive make calls in sql directory linked_server_sources: cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c diff --git a/SSL/NOTES b/SSL/NOTES new file mode 100644 index 00000000000..413c724c583 --- /dev/null +++ b/SSL/NOTES @@ -0,0 +1,376 @@ +Quick notes: +-------------------------------------------- +[tonu@x153 mysql-4.0]$ cat /etc/my.cnf +[mysqld] +ssl-ca=SSL/cacert.pem +ssl-cert=SSL/server-cert.pem +ssl-key=SSL/server-key.pem + +[mysql] +ssl-ca=SSL/cacert.pem +ssl-cert=SSL/client-cert.pem +ssl-key=SSL/client-key.pem + +[mysqldump] +ssl-ca=SSL/cacert.pem +ssl-cert=SSL/client-cert.pem +ssl-key=SSL/client-key.pem + +[tonu@x153 mysql-4.0]$ +-------------------------------------------- +To remove passwords from keyfiles: +[tonu@x153 SSL]$ openssl rsa -inform pem < server-req.pem > server-key.pem +read RSA key +Enter PEM pass phrase: +writing RSA key +[tonu@x153 SSL]$ +-------------------------------------------- +To run server: + +sql/mysqld --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --skip-grant --debug='d:t:O,-' > /tmp/mysqld.trace +-------------------------------------------- +To run client: + +client/mysql --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --debug='d:t:O,/tmp/client.trace' -h 127.0.0.1 +-------------------------------------------- +openssl s_client -host 127.0.0.1 -port 1111 -debug -verify 1 -cert ../SSL/client-cert.pem -key ../SSL/client-key.pem -CAfile ../SSL/cacert.pem -pause -showcerts -state + +-------------------------------------------- +openssl s_server -port 1111 -cert ../SSL/server-cert.pem -key ../SSL/server-key.pem + + + + +-------------------------------------------- + +CA stuff: + +[tonu@x153 bin]$ pwd +/usr/local/ssl/bin +[tonu@x153 bin]$ +[tonu@x153 bin]$ ./CA.sh +[tonu@x153 bin]$ ./CA.sh -h +usage: CA -newcert|-newreq|-newca|-sign|-verify +[tonu@x153 bin]$ +[root@x153 bin]# ./CA.sh -newca +CA certificate filename (or enter to create) + +Making CA certificate ... +Using configuration from /usr/lib/ssl/openssl.cnf +Generating a 1024 bit RSA private key +.++++++ +................++++++ +writing new private key to './demoCA/private/./cakey.pem' +Enter PEM pass phrase: +Verifying password - Enter PEM pass phrase: +phrase is too short, needs to be at least 4 chars +Enter PEM pass phrase: +Verifying password - Enter PEM pass phrase: +----- +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +ountry Name (2 letter code) [AU]:FI +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []:Helsinki +Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL Finland AB +Organizational Unit Name (eg, section) []: +Common Name (eg, YOUR name) []:Tonu Samuel +Email Address []:tonu@mysql.com +[root@x153 bin]# +[root@x153 bin]# ls -la demoCA/ +total 13 +drwxr-xr-x 6 root root 232 Jun 24 18:50 ./ +drwxr-xr-x 3 root root 2136 Jun 24 18:41 ../ +-rw-r--r-- 1 root root 1241 Jun 24 18:50 cacert.pem +drwxr-xr-x 2 root root 48 Jun 24 18:41 certs/ +drwxr-xr-x 2 root root 48 Jun 24 18:41 crl/ +-rw-r--r-- 1 root root 0 Jun 24 18:44 index.txt +drwxr-xr-x 2 root root 48 Jun 24 18:41 newcerts/ +drwxr-xr-x 2 root root 80 Jun 24 18:44 private/ +-rw-r--r-- 1 root root 3 Jun 24 18:44 serial +[root@x153 bin]# +[root@x153 bin]# ls -la demoCA/private/ +total 5 +drwxr-xr-x 2 root root 80 Jun 24 18:44 ./ +drwxr-xr-x 6 root root 232 Jun 24 18:50 ../ +-rw-r--r-- 1 root root 963 Jun 24 18:50 cakey.pem +[root@x153 bin]# +[root@x153 bin]# ./CA.sh -newreq +Using configuration from /usr/lib/ssl/openssl.cnf +Generating a 1024 bit RSA private key +..................++++++ +........................++++++ +writing new private key to 'newreq.pem' +Enter PEM pass phrase: <- new key password, not CA +Verifying password - Enter PEM pass phrase: +----- +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:EE +State or Province Name (full name) [Some-State]: +Locality Name (eg, city) []:Tallinn +Organization Name (eg, company) [Internet Widgits Pty Ltd]:Noname +Organizational Unit Name (eg, section) []: +Common Name (eg, YOUR name) []:Mr Noname +Email Address []:a@b.c + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +Request (and private key) is in newreq.pem +[root@x153 bin]# +[root@x153 bin]# ls -la newreq.pem +-rw-r--r-- 1 root root 1623 Jun 24 18:54 newreq.pem +[root@x153 bin]# +[root@x153 bin]# ./CA.sh -sign +Using configuration from /usr/lib/ssl/openssl.cnf +Enter PEM pass phrase: <- CA's one! +Check that the request matches the signature +Signature ok +The Subjects Distinguished Name is as follows +countryName :PRINTABLE:'EE' +stateOrProvinceName :PRINTABLE:'Some-State' +localityName :PRINTABLE:'Tallinn' +organizationName :PRINTABLE:'Noname' +commonName :PRINTABLE:'Mr Noname' +emailAddress :IA5STRING:'a@b.c' +Certificate is to be certified until Jun 24 15:50:23 2002 GMT (365 days) +Sign the certificate? [y/n]:y + + +1 out of 1 certificate requests certified, commit? [y/n]y +Write out database with 1 new entries +Data Base Updated +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com + Validity + Not Before: Jun 24 15:50:23 2001 GMT + Not After : Jun 24 15:50:23 2002 GMT + Subject: C=EE, ST=Some-State, L=Tallinn, O=Noname, CN=Mr Noname/Email=a@b.c + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ab:3b:7d:5b:6c:93:f6:46:1a:2c:46:73:6f:89: + 8a:99:bb:e9:6b:94:0d:74:aa:aa:c4:5c:a2:61:cf: + 56:bb:a1:a9:5a:37:c4:4e:b2:ec:5c:18:3a:a4:8d: + af:3d:23:66:7c:85:7f:d1:f2:e3:fc:16:a7:4c:a2: + d6:45:06:92:75:d8:a2:3b:f9:aa:77:da:26:b9:87: + e0:df:50:54:e4:36:9f:35:87:39:8e:a6:7c:3e:a8: + e4:49:1a:76:c2:6f:73:0b:22:93:2a:04:67:0d:7d: + ae:34:5c:fe:7c:29:b8:a2:fe:1e:ef:d1:0c:4d:dd: + 5b:7a:67:b0:0a:22:88:a0:af + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 83:D1:0D:52:0F:DE:61:2D:A6:10:20:B8:46:0C:77:D5:D2:D0:BE:20 + X509v3 Authority Key Identifier: + keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F + DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com + serial:00 + + Signature Algorithm: md5WithRSAEncryption + 60:85:f7:d0:54:2a:67:88:0e:37:a6:a8:8e:fd:a0:c9:a1:d7: + c6:fc:4c:2e:59:8d:88:6d:69:0a:b8:b2:67:5f:81:94:39:0e: + ab:67:fc:8b:62:de:85:f6:b3:8c:2d:1a:e3:dc:28:fc:f5:99: + 39:f0:3d:50:ca:88:c0:8e:f8:c2:02:5d:34:19:63:9f:c4:a2: + f6:a8:81:c9:8d:6d:bd:c4:42:4a:0c:49:5a:cc:24:ea:65:80: + dd:79:20:89:9e:ea:6b:80:7a:86:f9:bb:6d:24:3c:80:13:5b: + e6:16:fc:3d:8d:f6:16:ea:33:25:c6:90:20:81:a4:b0:15:2e: + 9c:1c +-----BEGIN CERTIFICATE----- +MIIDfjCCAuegAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx +EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK +ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG +SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTU1MDIzWhcNMDIwNjI0 +MTU1MDIzWjBvMQswCQYDVQQGEwJFRTETMBEGA1UECBMKU29tZS1TdGF0ZTEQMA4G +A1UEBxMHVGFsbGlubjEPMA0GA1UEChMGTm9uYW1lMRIwEAYDVQQDEwlNciBOb25h +bWUxFDASBgkqhkiG9w0BCQEWBWFAYi5jMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCrO31bbJP2RhosRnNviYqZu+lrlA10qqrEXKJhz1a7oalaN8ROsuxcGDqk +ja89I2Z8hX/R8uP8FqdMotZFBpJ12KI7+ap32ia5h+DfUFTkNp81hzmOpnw+qORJ +GnbCb3MLIpMqBGcNfa40XP58Kbii/h7v0QxN3Vt6Z7AKIoigrwIDAQABo4IBETCC +AQ0wCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg +Q2VydGlmaWNhdGUwHQYDVR0OBBYEFIPRDVIP3mEtphAguEYMd9XS0L4gMIGyBgNV +HSMEgaowgaeAFKUK1nK13+TCK3sHXtNNUgfhg2t/oYGLpIGIMIGFMQswCQYDVQQG +EwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMISGVsc2lua2kxGTAX +BgNVBAoTEE15U1FMIEZpbmxhbmQgQUIxFDASBgNVBAMTC1RvbnUgU2FtdWVsMR0w +GwYJKoZIhvcNAQkBFg50b251QG15c3FsLmNvbYIBADANBgkqhkiG9w0BAQQFAAOB +gQBghffQVCpniA43pqiO/aDJodfG/EwuWY2IbWkKuLJnX4GUOQ6rZ/yLYt6F9rOM +LRrj3Cj89Zk58D1QyojAjvjCAl00GWOfxKL2qIHJjW29xEJKDElazCTqZYDdeSCJ +nuprgHqG+bttJDyAE1vmFvw9jfYW6jMlxpAggaSwFS6cHA== +-----END CERTIFICATE----- +Signed certificate is in newcert.pem +[root@x153 bin]# ls -la demoCA/newcerts/ +total 5 +drwxr-xr-x 2 root root 72 Jun 24 18:58 ./ +drwxr-xr-x 6 root root 296 Jun 24 18:58 ../ +-rw-r--r-- 1 root root 3533 Jun 24 18:58 01.pem +[root@x153 bin]# +[root@x153 mysql-4.0]# ./sql/mysqld --ssl-cert=SSL/server-cert.pem --ssl-ca=SSL/cacert.pem --ssl-ke +y=SSL/server-req.pem -L /home/tonu/mysql-4.0/sql/share/english/ -u root +Enter PEM pass phrase: +./sql/mysqld: ready for connections +[tonu@x153 mysql-4.0]$ client/mysql --ssl-key=SSL/client-req.pem --ssl-ca=SSL/cacert.pem --ssl-cert +=SSL/client-cert.pem +Enter PEM pass phrase: +ERROR: + +[tonu@x153 mysql-4.0]$ + + + + +-8<------------------------ +SSL encrypts data between MySQL server and client. + +You need openssl (formerly SSLeay) for MySQL SSL support. Development +and testing was done on openssl version 0.9.3a + +To compile MySQL one must do: +./configure --with-openssl=/usr + +or + +./configure --with-openssl=yes + +There are sample keys and certificates included with MySQL tarball in +directory ./SSL. They are meant to be for quick start and +testing only. Using them in production environment means same as not +using encryption. This is because private keys are publicly +accessible for everyone. You must use openssl distribution for new key +and certificate generation for both client and server. + +----------- for manual: --------------------- +*New API calls:* + +mysql_ssl_set() - Set SSL properties (key, certificate, +certificates authority certificate). Must be called before +mysql_real_connect(); +mysql_ssl_clear() - Clear and free resources occupied by +mysql_ssl_set() API call. +char *mysql_ssl_cipher(MYSQL *) - returns cipher in use. For example +"DES-CDC3-SHA" means that you have combined triple DES symmetric +algorithm and SHA +hashing algorithm. + + +*New command line switches:* +--ssl Use SSL for connection (automatically set with +other flags. This means one can use encrypted connection without strong +cryptological authentication. Normally one must use all switches +together including ssl-key, ssl-cert and ssl-ca and never mind about +--ssl because this is assumed by defult if any of them (--ssl-...) +included. +--ssl-key X509 key in PEM format (implies --ssl) +--ssl-cert X509 cert in PEM format (implies --ssl) +--ssl-ca CA file in PEM format (check OpenSSL docs, +implies --ssl) +--ssl-capath CA directory (check OpenSSL docs, implies --ssl + ---------------- + This is about using SSL in MySQL privilege system. My idea is to make + possible use of x509 certificates and keys instead of MySQL native + passwords +Some basic theory about crypt, SSL and x509: +x509 is standard for certificates. SSL is standard for secure +communication. Certificates are issued by someone anyone can trust. This +trusted party is called "Certificate Authority" or "CA". This is +someone, we MUST trust. Everyone must have some "fingerprint" of CA (so +called "CA certificate" or "CA cert") using which one can verify +authenticity of other +certificates issued by this CA. CA uses his power to give certificates +to persons (they can be physical (like "monty") or logical (like some +process). Person is identified by "subject" like +"/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client bogus certificate/CN=Tonu +Samuel/Email=<EMAIL: PROTECTED>". and signed cryptologically. This sign can be +verified using CA-cert. So, if we trust CA, then we can trust identity +of user. +There can be many CA-s (usually not but who knows). Also there can be +some users we don`t trust or have different privileges. This means we +must have one table to hold CA-certs and other table to hold so called +"subjects" (users). I think it`s a good idea to use existing structure +of host/user/db/field and add some x509 relationship. Then we can +use usual simple user/host pair or x509 subject/CA pair. +So I think user must grant rights using old method GRANT blabla ON +blabla TO blabla IDENTIFIED BY blabla +or new way: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla +IDENTIFIED BY X509 SUBJECT "/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client +bogus certificate/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>" AND ISSUER +"/C=EE/ST=Harjumaa/L=Tallinn/O=TCX AB/CN=Tonu +Samuel/Email=<EMAIL: PROTECTED>"; +-----------8<--------------------------- +Please note the difference in Subject and Issuer. This command requests +user to authenticate itself with exact subject and exact certificate +issuer. Next possibility is just have any certificate of some good CA: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla IDENTIFIED BY X509 ISSUER +"/C=EE/ST=Harjumaa/L=Tallinn/O=TCX +AB/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>"; +-----------8<--------------------------- +or if any registered CA is good enough (usual case when only one CA is +registered) +but we care about exact user, then something like: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla IDENTIFIED BY X509 SUBJECT +"/C=EE/ST=Harjumaa/L=Tallinn/O=MySQL client +bogus certificate/CN=Tonu Samuel/Email=<EMAIL: PROTECTED>"; +-----------8<--------------------------- +And case if user must authenticate itself but we don`t care about exact +person until he have some certificate issued by CA registered in our +system: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla IDENTIFIED BY X509; +-----------8<--------------------------- +Then additionally we need one exception. Let`s assume we need SSL +encryption +for preventing eavesdropping but we don`t care who it is at all. We need +privilege to exclude all non-SSL users but we accept anyone using SSL. +How +this must be done in GRANT syntax? Maybe: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla +IDENTIFIED BY blabla AND USING SSL +-----------8<--------------------------- +But maybe we want to add in future possibility to check different +algorithms and key lengths? Something like: +-----------8<--------------------------- +GRANT blabla ON blabla TO blabla IDENTIFIED BY blabla AND USING SSL WITH +CIPHER "DES-CBC3-SHA" OR "DES-CBC3-MD5" +-----------8<--------------------------- +Also we need some command to include/exclude CA certificates. This must +be some commands like INSERT/DELETE/UPDATE/REPLACE to do it. +All examples is given for clarify my problem. I asking for help because +I don`t know +any similar command in other SQL-s. +------------8<------------------------ + +So, at moment SSL communications is ready and working. I don`t have this +command iterface at moment yet and this can be changed a lot if someone +can suggest good idea or reason to change them. We are ready to listen +every opinion. +About Kerberos: I just don`t know much about it. I have to read this +again before I can comment. I never used it itself and forgot most of +theory. Sorry. Anyway now the problem/need is known and I will put +thinking about this in personal TODO. + + diff --git a/SSL/cacert.pem b/SSL/cacert.pem new file mode 100644 index 00000000000..862e07114c5 --- /dev/null +++ b/SSL/cacert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAtGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx +EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK +ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG +SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTU0MzE4WhcNMDIwNjI0 +MTU0MzE4WjCBhTELMAkGA1UEBhMCRkkxEzARBgNVBAgTClNvbWUtU3RhdGUxETAP +BgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQKExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYD +VQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9udUBteXNxbC5jb20w +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJz9FCvWX8c+Xr6mxzfZvPainIPT +ODNsQ0f2kAs0epP+peUn4LHxLybp2dkUHTtJLXyUyk7cXfnUd+0fRazK2/Vz48bZ +swGwg9Rhg3P02Ku+CMWYulHzN6uVRzfrDUSkDoky2DGL3A6B8P4JRc2qcr+kjhh5 +6r1VJlXs9N3DqeEdAgMBAAGjgeUwgeIwHQYDVR0OBBYEFKUK1nK13+TCK3sHXtNN +Ugfhg2t/MIGyBgNVHSMEgaowgaeAFKUK1nK13+TCK3sHXtNNUgfhg2t/oYGLpIGI +MIGFMQswCQYDVQQGEwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMI +SGVsc2lua2kxGTAXBgNVBAoTEE15U1FMIEZpbmxhbmQgQUIxFDASBgNVBAMTC1Rv +bnUgU2FtdWVsMR0wGwYJKoZIhvcNAQkBFg50b251QG15c3FsLmNvbYIBADAMBgNV +HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAI+YJKoa+IP3WYr8iLcVk5j7lZ9D +GS8reuALafnE7VX1xMlXP5EnJjT7YYYmtiB2tYj7+eQ+ajRXWWyY5NtO5ob+dm8z +OBX43v08C5vNSAFpwZWTutzb0nSd8kOABGJ04MBDJZk8QNkTfU6C7c3ZJ/gW8Guv +I+cxfz6oCYEfKLBN +-----END CERTIFICATE----- diff --git a/SSL/client-cert.pem b/SSL/client-cert.pem new file mode 100644 index 00000000000..cab2a635d9f --- /dev/null +++ b/SSL/client-cert.pem @@ -0,0 +1,67 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com + Validity + Not Before: Jun 24 16:03:20 2001 GMT + Not After : Jun 24 16:03:20 2002 GMT + Subject: C=EE, ST=Some-State, L=Tallinn, O=MySQL demo client certificate, CN=Tonu Samuel/Email=tonu@mysql.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:e8:d4:52:cd:4e:bb:96:16:3a:f0:89:6b:90:4c: + db:e0:30:75:5a:02:72:62:bf:ed:da:be:09:e8:80: + db:80:54:30:d6:75:ed:e3:10:a5:15:44:5b:29:91: + 12:fe:0c:b7:76:4d:e9:5f:56:5c:45:3c:ad:b2:71: + 2d:6a:7a:cb:bc:04:80:08:74:d6:7d:f6:7c:5c:76: + db:35:c4:f6:f5:d8:d4:89:9f:9d:cc:3f:4e:3f:73: + c1:3e:41:7e:4e:09:bf:ea:1a:d9:a2:13:0d:d1:0c: + da:d8:f4:9b:b8:54:21:17:ae:d7:b3:02:61:87:a9: + 01:ff:f4:fe:9c:7a:fc:67:43 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + BC:FB:BB:8F:C4:85:BA:5F:A8:F2:C3:3D:C9:0F:DB:16:E7:13:BC:B2 + X509v3 Authority Key Identifier: + keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F + DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com + serial:00 + + Signature Algorithm: md5WithRSAEncryption + 1c:e0:87:2c:2f:b3:a4:39:44:7f:96:7b:2f:c9:1f:91:84:0b: + 9f:d0:0a:f8:40:70:d0:dd:bd:91:0a:c6:d5:ac:8f:51:77:9c: + 35:28:e8:b6:5f:57:9e:5c:b5:9b:ae:5d:3d:7c:05:45:2e:89: + 3a:03:e1:f2:00:cb:c1:ed:3e:48:3b:5f:4e:50:d2:b4:a5:36: + 0f:1a:dc:79:49:1e:03:2f:27:c1:e4:62:d6:ef:3f:ab:2e:ab: + dd:e5:bc:cb:20:a3:dd:ab:81:69:26:9c:03:42:1b:4c:b7:aa: + 57:6d:2a:de:c0:5e:6e:74:d0:83:90:ec:ad:bb:ba:f0:cc:cf: + 41:3d +-----BEGIN CERTIFICATE----- +MIIDoTCCAwqgAwIBAgIBAzANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx +EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK +ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG +SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTYwMzIwWhcNMDIwNjI0 +MTYwMzIwWjCBkTELMAkGA1UEBhMCRUUxEzARBgNVBAgTClNvbWUtU3RhdGUxEDAO +BgNVBAcTB1RhbGxpbm4xJjAkBgNVBAoTHU15U1FMIGRlbW8gY2xpZW50IGNlcnRp +ZmljYXRlMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9u +dUBteXNxbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOjUUs1Ou5YW +OvCJa5BM2+AwdVoCcmK/7dq+CeiA24BUMNZ17eMQpRVEWymREv4Mt3ZN6V9WXEU8 +rbJxLWp6y7wEgAh01n32fFx22zXE9vXY1Imfncw/Tj9zwT5Bfk4Jv+oa2aITDdEM +2tj0m7hUIReu17MCYYepAf/0/px6/GdDAgMBAAGjggERMIIBDTAJBgNVHRMEAjAA +MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd +BgNVHQ4EFgQUvPu7j8SFul+o8sM9yQ/bFucTvLIwgbIGA1UdIwSBqjCBp4AUpQrW +crXf5MIrewde001SB+GDa3+hgYukgYgwgYUxCzAJBgNVBAYTAkZJMRMwEQYDVQQI +EwpTb21lLVN0YXRlMREwDwYDVQQHEwhIZWxzaW5raTEZMBcGA1UEChMQTXlTUUwg +RmlubGFuZCBBQjEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW +DnRvbnVAbXlzcWwuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBABzghywvs6Q5RH+W +ey/JH5GEC5/QCvhAcNDdvZEKxtWsj1F3nDUo6LZfV55ctZuuXT18BUUuiToD4fIA +y8HtPkg7X05Q0rSlNg8a3HlJHgMvJ8HkYtbvP6suq93lvMsgo92rgWkmnANCG0y3 +qldtKt7AXm500IOQ7K27uvDMz0E9 +-----END CERTIFICATE----- diff --git a/SSL/client-key.pem b/SSL/client-key.pem new file mode 100644 index 00000000000..7672939b60a --- /dev/null +++ b/SSL/client-key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDo1FLNTruWFjrwiWuQTNvgMHVaAnJiv+3avgnogNuAVDDWde3j +EKUVRFspkRL+DLd2TelfVlxFPK2ycS1qesu8BIAIdNZ99nxcdts1xPb12NSJn53M +P04/c8E+QX5OCb/qGtmiEw3RDNrY9Ju4VCEXrtezAmGHqQH/9P6cevxnQwIDAQAB +AoGBANxd4cUaaOfkQILbvigE5vMpSlkYCcW3XNv1lJEwLREoHlVNpwuL/IPFf/c2 +rWAxDw/1LBYlOg36IXjMMC0g7mRHHoJhdJaFLGdlfclYQvqQ+8JAsAv6UNC63+pn +B5sZOxOuoj7lYN+D9mFVD4qTo3eTUYEOvvmS1j3hCsD2nNNBAkEA+lJUs7Y3KjCF +COZ7XQCkC47rVzkdZ5ey1Z+vVw5SrnUvj6n9i0NEax1jX6JPIhPU7+x90KFkt0ki +pKHd7UQ04wJBAO4caWNnYvmIorCRDy9Q/iAAow5WC6fQlkSlBIe3lRme6Ne8Yxaq +BzlSGYu1ndPkTGEa9PFNNCJm7RtvCBFx8iECQQCkdUzi2Rc7J69vnoV0H8SnN1mU +75hLBBZhVU1MY8OcjK8XsvY59ZLQ0PkFzswwtljS3Ev4suBJrsoM4a+9f29DAkEA +5NTrN3vZc6SrbXLLHBcDUrAqBBIPe4SLlYbdVqzInunILeS/eb2H2b+cC1dMSaHj +AYONmQUwMEuoXTAUmede4QJARK6jEslg/ev8BtMvITP2b6pRCb1w8lOtT5u5Bwnc +NpI3suqSQSQPtRSWQYcdyxrKr2TQEZU7h8R9bVB4b0qAmQ== +-----END RSA PRIVATE KEY----- diff --git a/SSL/client-req.pem b/SSL/client-req.pem new file mode 100644 index 00000000000..ef11a22165f --- /dev/null +++ b/SSL/client-req.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,8CE2AB38FB50D4B9 + +rrnYZLUKlzV4U7+wqe5CWzTd4RLJb5h4M77aBRQfuHGejSaRsskN2ffpO8uQEAYM +WTJSRC+NO+jDMBZhzt1ktWqCs8d6l6azHoBybIrMJsbUhwybm+OiOfp23RrbNoS/ +S4fsgNdAAGhsRvKDdsItCyYvdH8nTzn+g9r/z2V4tOOXd6MYuT42XA6Uz2tis2SZ +GWEGa7mAweApzSiibE+pzjPS+fdX4E12n6NCVYLhn1JuvzVva/KFSebs4Wh75miC +WvRgkt/5eDQn+vkV67hE3I6p9pPcLh1+PMfaQ25U8VM/r7ejnVFWm7teGH6GKPKJ +cU+PYfblyWcgtiO/fwfGMIqSyNtHj/C3VFVie5D1MTJzBopiPGEcfz00LjBccjjh +j1meTRVN8pMZTgkxlnIFwbU6TPPvx8a9urFVQIJ4z8r2EMvYh5Cqpq87+lH9Pn0C +vzCl78Tz5QLghXNnMbbdD2aPP0PwPEXgh86iZxo06g85n0l26WUzYJlWzBYD4DrF +SbnEUAftTujEOm6MqJNLpJN6UPOtq/HvSaHl1bykGK+zU4gqHj0ur03HlF0l4xNg +OfsoNsJV+O9RUUJ0+D5eqUALJjN8TCV1wNMXOVzr/ue3QCVdlWVfZY4RPffwK9Yp +Fh52T7a2v+shhqZUQNtFDAg50Ac7deUthSWNmi5N680POnJg9KdtBdMhYLa1j3rP +D9oasSK0ugevHuQ6wUiD/95CzZlJXE9K4kTTYmaRk5MTWXhFQxdqHZo1v+pGtaNI +f+/E7q7BiNesSt31U/vkX0Tm3oJ1dgOnS8M2uxiYiKH2mJ/E32tZKw== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE REQUEST----- +MIIB0jCCATsCAQAwgZExCzAJBgNVBAYTAkVFMRMwEQYDVQQIEwpTb21lLVN0YXRl +MRAwDgYDVQQHEwdUYWxsaW5uMSYwJAYDVQQKEx1NeVNRTCBkZW1vIGNsaWVudCBj +ZXJ0aWZpY2F0ZTEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW +DnRvbnVAbXlzcWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo1FLN +TruWFjrwiWuQTNvgMHVaAnJiv+3avgnogNuAVDDWde3jEKUVRFspkRL+DLd2Telf +VlxFPK2ycS1qesu8BIAIdNZ99nxcdts1xPb12NSJn53MP04/c8E+QX5OCb/qGtmi +Ew3RDNrY9Ju4VCEXrtezAmGHqQH/9P6cevxnQwIDAQABoAAwDQYJKoZIhvcNAQEE +BQADgYEAvENK1JAQfC8xnrFGw2IxfUmUwlRidiRtYTgtVfTr7vA+m4WaaKioni6E +PQXjcvl6kfyRoxc4qWsGi3T7QM2RnvCtbwR2NGSIKX1cBTS31RMr12NSAeXn6Twz +ZwSZ55EHj9N2hArTPNlVjxvDQX3D6/ZBi6JnHAxXigzDqhArgjU= +-----END CERTIFICATE REQUEST----- diff --git a/SSL/run-client b/SSL/run-client new file mode 100755 index 00000000000..f3b29eb273b --- /dev/null +++ b/SSL/run-client @@ -0,0 +1,10 @@ +#! /bin/sh + +cmd () { + echo $* + $* +} + +client/mysql --port=4407 --socket=/tmp/test.mysql.sock --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/client-cert.pem --ssl-key=SSL/client-key.pem --debug='d:t:O,/tmp/client.trace' -h 127.0.0.1 -u root +#--execute="select version();show status" + diff --git a/SSL/run-server b/SSL/run-server new file mode 100755 index 00000000000..e90a7644b83 --- /dev/null +++ b/SSL/run-server @@ -0,0 +1,9 @@ +#! /bin/sh + +cmd () { + echo $* + $* +} + +cmd sql/mysqld --port=4407 --socket=/tmp/test.mysql.sock --ssl-ca=SSL/cacert.pem --ssl-cert=SSL/server-cert.pem --ssl-key=SSL/server-key.pem --debug='d:t:O,/tmp/mysqld.trace' -uroot >& /tmp/mysqld.output + diff --git a/SSL/server-cert.pem b/SSL/server-cert.pem new file mode 100644 index 00000000000..069063a9de9 --- /dev/null +++ b/SSL/server-cert.pem @@ -0,0 +1,67 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=FI, ST=Some-State, L=Helsinki, O=MySQL Finland AB, CN=Tonu Samuel/Email=tonu@mysql.com + Validity + Not Before: Jun 24 16:02:28 2001 GMT + Not After : Jun 24 16:02:28 2002 GMT + Subject: C=EE, ST=Some-State, L=Tallinn, O=MySQL server demo certificate, CN=Tonu Samuel/Email=tonu@mysql.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:9e:ac:8d:d8:1d:9c:b2:fd:88:96:2c:ba:42:53: + fa:5d:bd:85:8a:e5:ca:d3:0f:c0:01:3c:f2:92:46: + 4f:d9:80:ae:2a:89:cf:ef:e8:d4:65:fc:f6:f5:3a: + 26:4c:29:db:06:fa:34:a1:87:f3:97:b5:3c:94:f1: + 84:05:ac:ad:57:25:d9:02:db:00:71:e0:a9:aa:b4: + 1d:29:36:5e:a9:a4:0d:f2:45:b9:83:74:2b:45:f3: + e2:23:bc:e7:5c:e6:11:b6:f6:dd:c4:ac:ed:65:42: + 2c:39:47:2a:c9:eb:5f:45:03:10:ab:23:bc:ca:5c: + 82:9a:b7:b3:6d:67:18:d2:c7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 94:68:BF:DA:F6:E2:09:EF:3A:C8:27:AE:D7:B7:02:F0:DC:4B:C1:3B + X509v3 Authority Key Identifier: + keyid:A5:0A:D6:72:B5:DF:E4:C2:2B:7B:07:5E:D3:4D:52:07:E1:83:6B:7F + DirName:/C=FI/ST=Some-State/L=Helsinki/O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@mysql.com + serial:00 + + Signature Algorithm: md5WithRSAEncryption + 8c:1a:90:70:f6:1a:70:0e:c9:28:93:74:e2:2b:b8:2a:d0:ce: + 40:15:e8:af:44:f8:89:16:20:f5:c2:b9:ed:aa:4e:3c:40:e2: + 9c:62:aa:48:98:ac:17:84:ef:35:72:59:43:09:35:17:c5:9a: + 3e:3d:ef:97:bf:57:f2:2a:f6:56:5d:a4:7c:68:58:b9:d6:9b: + 0f:57:0e:55:22:17:b0:b7:77:27:4f:da:b3:88:c1:6d:d6:8f: + 31:ec:0d:a2:25:60:66:2f:0f:86:8a:d6:08:b8:71:b1:b5:70: + 60:04:56:96:ff:bd:5e:ed:94:bc:44:bd:24:e0:2f:90:e5:23: + 51:4e +-----BEGIN CERTIFICATE----- +MIIDoTCCAwqgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBhTELMAkGA1UEBhMCRkkx +EzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCEhlbHNpbmtpMRkwFwYDVQQK +ExBNeVNRTCBGaW5sYW5kIEFCMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqG +SIb3DQEJARYOdG9udUBteXNxbC5jb20wHhcNMDEwNjI0MTYwMjI4WhcNMDIwNjI0 +MTYwMjI4WjCBkTELMAkGA1UEBhMCRUUxEzARBgNVBAgTClNvbWUtU3RhdGUxEDAO +BgNVBAcTB1RhbGxpbm4xJjAkBgNVBAoTHU15U1FMIHNlcnZlciBkZW1vIGNlcnRp +ZmljYXRlMRQwEgYDVQQDEwtUb251IFNhbXVlbDEdMBsGCSqGSIb3DQEJARYOdG9u +dUBteXNxbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ6sjdgdnLL9 +iJYsukJT+l29hYrlytMPwAE88pJGT9mAriqJz+/o1GX89vU6Jkwp2wb6NKGH85e1 +PJTxhAWsrVcl2QLbAHHgqaq0HSk2XqmkDfJFuYN0K0Xz4iO851zmEbb23cSs7WVC +LDlHKsnrX0UDEKsjvMpcgpq3s21nGNLHAgMBAAGjggERMIIBDTAJBgNVHRMEAjAA +MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd +BgNVHQ4EFgQUlGi/2vbiCe86yCeu17cC8NxLwTswgbIGA1UdIwSBqjCBp4AUpQrW +crXf5MIrewde001SB+GDa3+hgYukgYgwgYUxCzAJBgNVBAYTAkZJMRMwEQYDVQQI +EwpTb21lLVN0YXRlMREwDwYDVQQHEwhIZWxzaW5raTEZMBcGA1UEChMQTXlTUUwg +RmlubGFuZCBBQjEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW +DnRvbnVAbXlzcWwuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAIwakHD2GnAOySiT +dOIruCrQzkAV6K9E+IkWIPXCue2qTjxA4pxiqkiYrBeE7zVyWUMJNRfFmj4975e/ +V/Iq9lZdpHxoWLnWmw9XDlUiF7C3dydP2rOIwW3WjzHsDaIlYGYvD4aK1gi4cbG1 +cGAEVpb/vV7tlLxEvSTgL5DlI1FO +-----END CERTIFICATE----- diff --git a/SSL/server-key.pem b/SSL/server-key.pem new file mode 100644 index 00000000000..44137ca1c94 --- /dev/null +++ b/SSL/server-key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCerI3YHZyy/YiWLLpCU/pdvYWK5crTD8ABPPKSRk/ZgK4qic/v +6NRl/Pb1OiZMKdsG+jShh/OXtTyU8YQFrK1XJdkC2wBx4KmqtB0pNl6ppA3yRbmD +dCtF8+IjvOdc5hG29t3ErO1lQiw5RyrJ619FAxCrI7zKXIKat7NtZxjSxwIDAQAB +AoGAA51gudyq1jUKaIlqUNqC6KHJqglkHnzMXfrad9ScOxNAZH2xPADs3cnuglWp +y7BkaftHOarUNM+PKsF5xXtSk5F9UUV+7h2FtPZYUshUgn5hkGZP12otxJMP0cpg +Yt6brQxuOIe/r/Kt5r3nKpp4pyFLX2fGWQq7pSjdkgSZSOECQQDJ9MgbCXd81yde +eo3+YmUPBEQ9d7mivQsyPHMOHLPJKR42N4npdR1zLDBYK5lFzJeQH1y0Uce3O8eL +hM8hkA1XAkEAySKvNTaosbLhShkRazQyQQJYJg0F/93lkQ33ou4crru7Mvi2OZK9 +B3BGAmNpSv6ZOZYjM0aE8lGlTaoYJ9GQEQJAGJDyFnfcVQ9G9rMpupv1dxIpyuBZ +cHZWelHoHPtY00txJV80I3Xfkzb42oDTMC5m8V0fRb/870kSSOJq38ZKGQJBAIgq +wxLzfiFPSNYxQmmhXKRGQgcAqh8eylv5aL0VFrX0wjcvya4QeYifqcXUJ2RuGK2z +xwDfrQGf5Jk/njrW1QECQAUofd1l9DLDifRP1j9sjUdwz0fvqQ0o6sbt39PBl1ot +IHdc3nf9z0ft+KOG1CT/M9jYo9SzE9Z6IfwmHxxpY0s= +-----END RSA PRIVATE KEY----- diff --git a/SSL/server-req.pem b/SSL/server-req.pem new file mode 100644 index 00000000000..4cd6610e735 --- /dev/null +++ b/SSL/server-req.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,6CBD09E71246DC01 + +byRzq5+j3r8FX2kQerTUZT5Bw/N6zrN3cmH6NHGJcrqD+vcPdtWf+Rk+mpNXgSQn +ldkfmniU/htzJ0cUV+KE229Qx10Hx9mIJIbf0Y/rBCUBuaXWVrQB36W9w3rkNPFA +EEuRMkreOJF42RD16+NBJv+RcHIGzGejXecJKUGF5DKlN0U8YHXnkXTQl54kIdr0 +H7rTrvJygwPk9/ik0M9/vmwduAMvTaHDmvgeolpMlJkxwz8vYkbUnFFJZhB6XNCb +1w3lJ0EmRJicK5BnZmCEmgt8xiv0PAtg00jBbwddQbn1reAyViBtBT9iXdusHXS5 +Po63rSt7r3MO8aetcMQ6FkklH+ChuS/vFoNY57AwrzF4uEI4GSoZP0ESrRC5Ar5W +Lzg/HrQAWbPCRlb6Jj3db1woRzFS8joOashROsZdeV/5P4Emhc6J7QMTvB1OHAhQ +ugOJazJtxjg0DN8+9cM1wtHI7N89PLHhOg13LZNLeeehzIlPwKI2JLqXUc6oR407 +i+S7GCqu7wU+if0Enux8Dj7yrvnTUiqVCL2dyKTS3sBq0Cm2UhbecHclor13y6no +y1o50TKKD6Zig2hZmSpqKznMxGMVIT36BE0aOMQUmk+aVnRuROclwTTL0ZNLzA+g +QRTRfQ6iNMf34ypqAMdAMPzDGLPycKuFdxVQxFEVaM2/mrdWFwVAqFsLvzyGvdrh +nkNyRgTWR/pfH9b3mXLqf6gMPNs764WhFIcZIDk9a4XBBUm2YDb2CxDzDCo/EUMA +jvIiU0Jt132SEHHF/wAka6d2DnwZ3vexRp6Tebv/uy9IlMLPE+68dw== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE REQUEST----- +MIIB0jCCATsCAQAwgZExCzAJBgNVBAYTAkVFMRMwEQYDVQQIEwpTb21lLVN0YXRl +MRAwDgYDVQQHEwdUYWxsaW5uMSYwJAYDVQQKEx1NeVNRTCBzZXJ2ZXIgZGVtbyBj +ZXJ0aWZpY2F0ZTEUMBIGA1UEAxMLVG9udSBTYW11ZWwxHTAbBgkqhkiG9w0BCQEW +DnRvbnVAbXlzcWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCerI3Y +HZyy/YiWLLpCU/pdvYWK5crTD8ABPPKSRk/ZgK4qic/v6NRl/Pb1OiZMKdsG+jSh +h/OXtTyU8YQFrK1XJdkC2wBx4KmqtB0pNl6ppA3yRbmDdCtF8+IjvOdc5hG29t3E +rO1lQiw5RyrJ619FAxCrI7zKXIKat7NtZxjSxwIDAQABoAAwDQYJKoZIhvcNAQEE +BQADgYEAlrUnGX4LYIiVjztHA4gUcOSVeEHCci2qEUq+7yY1JhAw54YDa2MLTTwa +cH+rXLHjN0MTNfv9tRxdSX+trk3pyvhgFjssD100dJkF83RfVv2tKg9kscVOGQp7 +MkwOnJjfAjQBlTbTOQM46BTjv2FgvsppkO3ViryI//YxKvj/628= +-----END CERTIFICATE REQUEST----- diff --git a/acconfig.h b/acconfig.h index c6a67ac7f26..341de4a2ceb 100644 --- a/acconfig.h +++ b/acconfig.h @@ -111,6 +111,9 @@ /* sigwait with one argument */ #undef HAVE_NONPOSIX_SIGWAIT +/* ORBIT */ +#undef HAVE_ORBIT + /* pthread_attr_setscope */ #undef HAVE_PTHREAD_ATTR_SETSCOPE @@ -160,9 +163,15 @@ /* new UNIXWARE7 threads that are not yet posix */ #undef HAVE_UNIXWARE7_POSIX +/* OpenSSL */ +#undef HAVE_OPENSSL + /* READLINE: */ #undef HAVE_USG_SIGHOLD +/* Virtual IO */ +#undef HAVE_VIO + /* Handling of large files on Solaris 2.6 */ #undef _LARGEFILE_SOURCE @@ -236,6 +245,9 @@ #undef USE_MB #undef USE_MB_IDENT +/* the pstack backtrace library */ +#undef USE_PSTACK + /* Use MySQL RAID */ #undef USE_RAID diff --git a/acinclude.m4 b/acinclude.m4 index 8fb3e986b11..82490f0e988 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -642,6 +642,150 @@ fi AC_MSG_RESULT($ac_cv_conv_longlong_to_float) ]) +AC_DEFUN(MYSQL_CHECK_CPU, +AC_CACHE_CHECK([if compiler supports optimizations for current cpu], mysql_cv_cpu,[ + +ac_save_CFLAGS="$CFLAGS" +if test -r /proc/cpuinfo ; then + cpuinfo="cat /proc/cpuinfo" + cpu_family=`$cpuinfo | grep 'cpu family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + cpu_vendor=`$cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` +fi +if test "$cpu_vendor" = "AuthenticAMD"; then + if test $cpu_family>=6; then + cpu_set="athlon pentiumpro k5 pentium i486 i386"; + elif test $cpu_family=5; then + cpu_set="k5 pentium i486 i386"; + elif test $cpu_family=4; then + cpu_set="i486 i386" + else + cpu_set="i386" + fi +elif test "$cpu_vendor" = "GenuineIntel"; then + if test $cpu_family>=6; then + cpu_set=" pentiumpro pentium i486 i386"; + elif test $cpu_family=5; then + cpu_set="pentium i486 i386"; + elif test $cpu_family=4; then + cpu_set="i486 i386" + else + cpu_set="i386" + fi +fi + +for ac_arg in $cpu_set; +do + CFLAGS="$ac_save_CFLAGS -mcpu=$ac_arg -march=$ac_arg -DCPU=$ac_arg" + AC_TRY_COMPILE([],[int i],mysql_cv_cpu=$ac_arg; break;, mysql_cv_cpu="unknown") +done + +if test "$mysql_cv_cpu" = "unknown" +then + CFLAGS="$ac_save_CFLAGS" + AC_MSG_RESULT(none) +else + AC_MSG_RESULT($mysql_cv_cpu) +fi +])) + +AC_DEFUN(MYSQL_CHECK_VIO, [ + AC_ARG_WITH([vio], + [\ + --with-vio Include the Virtual IO support], + [vio="$withval"], + [vio=no]) + + if test "$vio" = "yes" + then + vio_dir="vio" + vio_libs="../vio/libvio.la" + AC_DEFINE(HAVE_VIO) + else + vio_dir="" + vio_libs="" + fi + AC_SUBST([vio_dir]) + AC_SUBST([vio_libs]) +]) + + +AC_DEFUN(MYSQL_CHECK_OPENSSL, [ +AC_MSG_CHECKING(for OpenSSL) + AC_ARG_WITH([openssl], + [\ + --with-openssl Include the OpenSSL support], + [openssl="$withval"], + [openssl=no]) + + if test "$openssl" = "yes" + then + if test -n "$vio_dir" + then + AC_MSG_RESULT(yes) + openssl_libs="-lssl -lcrypto -L/usr/local/ssl/lib" + openssl_includes="-I/usr/local/ssl/include" + else + AC_MSG_ERROR([OpenSSL requires Virtual IO support (--with-vio)]) + fi + AC_DEFINE(HAVE_OPENSSL) + else + AC_MSG_RESULT(no) + openssl_libs="" + openssl_includes="" + fi + NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs" + AC_SUBST(openssl_libs) + AC_SUBST(openssl_includes) +]) + + +AC_DEFUN(MYSQL_CHECK_MYSQLFS, [ + AC_ARG_WITH([mysqlfs], + [\ + --with-mysqlfs Include the corba-based MySQL file system], + [mysqlfs="$withval"], + [mysqlfs=no]) + +dnl Call MYSQL_CHECK_ORBIT even if mysqlfs == no, so that @orbit_*@ +dnl get substituted. + MYSQL_CHECK_ORBIT + + if test "$mysqlfs" = "yes" + then + if test -n "$orbit_exec_prefix" + then + fs_dirs=fs + else + AC_MSG_ERROR([mysqlfs requires ORBit, the CORBA ORB]) + fi + else + fs_dirs= + fi + AC_SUBST([fs_dirs]) +]) + +AC_DEFUN(MYSQL_CHECK_ORBIT, [ +AC_MSG_CHECKING(for ORBit) +if test `which orbit-config` +then + orbit_exec_prefix=`orbit-config --exec-prefix` + orbit_includes=`orbit-config --cflags server` + orbit_libs=`orbit-config --libs server` + orbit_idl="$orbit_exec_prefix/bin/orbit-idl" + AC_MSG_RESULT(found!) + AC_DEFINE(HAVE_ORBIT) +else + orbit_exec_prefix= + orbit_includes= + orbit_libs= + orbit_idl= + AC_MSG_RESULT(not found) +fi +AC_SUBST(orbit_includes) +AC_SUBST(orbit_libs) +AC_SUBST(orbit_idl) +]) + dnl --------------------------------------------------------------------------- dnl Macro: MYSQL_CHECK_BDB dnl Sets HAVE_BERKELEY_DB if inst library is found diff --git a/client/Makefile.am b/client/Makefile.am index 380c9f2acbe..e39c663de15 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -16,7 +16,7 @@ # This file is public domain and comes with NO WARRANTY of any kind -INCLUDES = -I$(srcdir)/../include \ +INCLUDES = -I$(srcdir)/../include $(openssl_includes) \ -I../include -I$(srcdir)/.. -I$(top_srcdir) \ -I.. noinst_HEADERS = client_priv.h diff --git a/client/errmsg.c b/client/errmsg.c index 67cfe874f77..9f67a15dcb2 100644 --- a/client/errmsg.c +++ b/client/errmsg.c @@ -45,7 +45,13 @@ const char *client_errors[]= "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)", "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)", "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'" + "Got packet bigger than 'max_allowed_packet'", + "Embedded server", + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" + }; /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ @@ -73,7 +79,12 @@ const char *client_errors[]= "Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", "Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", "Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)", - "Obteve pacote maior do que 'max_allowed_packet'" + "Obteve pacote maior do que 'max_allowed_packet'", + "Embedded server", + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" }; #else /* ENGLISH */ @@ -99,7 +110,12 @@ const char *client_errors[]= "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'" + "Got packet bigger than 'max_allowed_packet'", + "Embedded server", + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" }; #endif diff --git a/client/insert_test.c b/client/insert_test.c index 640935d63b2..82609f68e4e 100644 --- a/client/insert_test.c +++ b/client/insert_test.c @@ -34,19 +34,13 @@ int main(int argc, char **argv) exit(1); } - if (!(sock = mysql_connect(&mysql,NULL,0,0))) + if (!(sock = mysql_real_connect(&mysql,NULL,NULL,NULL,argv[1],0,NULL,0))) { fprintf(stderr,"Couldn't connect to engine!\n%s\n",mysql_error(&mysql)); perror(""); exit(1); } - if (mysql_select_db(sock,argv[1])) - { - fprintf(stderr,"Couldn't select database %s!\n%s\n",argv[1], - mysql_error(sock)); - } - num = atoi(argv[2]); count = 0; while (count < num) diff --git a/client/mysql.cc b/client/mysql.cc index 96536c9d5f0..43df5037a68 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -19,9 +19,11 @@ * * Written by: * Michael 'Monty' Widenius - * Andi Gutmans <andi@zend.com> + * Andi Gutmans <andi@zend.com> * Zeev Suraski <zeev@zend.com> * Jani Tolonen <jani@mysql.com> + * Matt Wagner <mwagner@mysql.com> + * Jeremy Cole <jcole@mysql.com> * **/ @@ -33,6 +35,7 @@ #endif #include "my_readline.h" #include <signal.h> +#include <violite.h> const char *VER="11.15"; @@ -115,7 +118,7 @@ static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0, no_rehash=0,skip_updates=0,safe_updates=0,one_database=0, opt_compress=0, vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0, - opt_nopager=1, opt_outfile=0, no_named_cmds=1; + opt_xml=0,opt_nopager=1, opt_outfile=0, no_named_cmds=1; static uint verbose=0,opt_silent=0,opt_mysql_port=0; static my_string opt_mysql_unix_port=0; static int connect_flag=CLIENT_INTERACTIVE; @@ -126,6 +129,11 @@ static String glob_buffer,old_buffer; static int wait_time = 5; static STATUS status; static ulong select_limit,max_join_size,opt_connect_timeout=0; +static const char *xmlmeta[] = { + "&", "&", + "<", "<", + 0, 0 +}; static char default_pager[FN_REFLEN]; char pager[FN_REFLEN], outfile[FN_REFLEN]; FILE *PAGER, *OUTFILE; @@ -161,6 +169,9 @@ static int sql_connect(char *host,char *database,char *user,char *password, uint silent); static int put_info(const char *str,INFO_TYPE info,uint error=0); static void safe_put_field(const char *pos,ulong length); +static const char *array_value(const char **array, char *key); +static void xmlencode(char *dest, char *src); +static void my_chomp(char *end); static void init_pager(); static void end_pager(); static void init_tee(); @@ -245,6 +256,7 @@ static bool add_line(String &buffer,char *line,char *in_string); static void remove_cntrl(String &buffer); static void print_table_data(MYSQL_RES *result); static void print_table_data_html(MYSQL_RES *result); +static void print_table_data_xml(MYSQL_RES *result); static void print_tab_data(MYSQL_RES *result); static void print_table_data_vertically(MYSQL_RES *result); static ulong start_timer(void); @@ -311,9 +323,19 @@ int main(int argc,char *argv[]) mysql_thread_id(&mysql),mysql_get_server_info(&mysql)); put_info((char*) glob_buffer.ptr(),INFO_INFO); +#ifdef HAVE_OPENSSL + if(mysql.net.vio->ssl_ && SSL_get_cipher(mysql.net.vio->ssl_)) { + sprintf((char*) glob_buffer.ptr(), + "SSL cipher in use is %s\n", SSL_get_cipher(mysql.net.vio->ssl_)); + put_info((char*) glob_buffer.ptr(),INFO_INFO); + } else + put_info("SSL is not in use\n",INFO_INFO); +#endif /* HAVE_OPENSSL */ + + #ifdef HAVE_READLINE initialize_readline(my_progname); - if (!status.batch && !quick && !opt_html) + if (!status.batch && !quick && !opt_html && !opt_xml) { /*read-history from file, default ~/.mysql_history*/ if (getenv("MYSQL_HISTFILE")) @@ -350,8 +372,11 @@ sig_handler mysql_end(int sig) { if (connected) mysql_close(&mysql); + else + mysql_ssl_clear(&mysql); /* SSL data structres should be freed + even if connection was not made */ #ifdef HAVE_READLINE - if (!status.batch && !quick && ! opt_html) + if (!status.batch && !quick && !opt_html && !opt_xml) { /* write-history */ if (verbose) @@ -392,6 +417,7 @@ static struct option long_options[] = {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, '?'}, {"html", no_argument, 0, 'H'}, + {"xml", no_argument, 0, 'X'}, {"host", required_argument, 0, 'h'}, {"ignore-spaces", no_argument, 0, 'i'}, {"no-auto-rehash",no_argument, 0, 'A'}, @@ -486,6 +512,7 @@ static void usage(int version) -i, --ignore-space Ignore space after function names.\n\ -h, --host=... Connect to host.\n\ -H, --html Produce HTML output.\n\ + -X, --xml Produce XML output.\n\ -L, --skip-line-numbers\n\ Don't write line number for errors.\n"); #ifndef __WIN__ @@ -560,7 +587,7 @@ static int get_options(int argc, char **argv) set_all_changeable_vars(changeable_vars); while ((c=getopt_long(argc,argv, - (char*) "?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::", + (char*) "?ABCD:LfgGHXinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::", long_options, &option_index)) != EOF) { switch(c) { @@ -681,6 +708,7 @@ static int get_options(int argc, char **argv) case 'G': no_named_cmds=0; break; case 'g': no_named_cmds=1; break; case 'H': opt_html=1; break; + case 'X': opt_xml=1; break; case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break; case 'B': if (!status.batch) @@ -1448,6 +1476,8 @@ com_go(String *buffer,char *line __attribute__((unused))) init_pager(); if (opt_html) print_table_data_html(result); + else if (opt_xml) + print_table_data_xml(result); else if (vertical) print_table_data_vertically(result); else if (opt_silent && verbose <= 2 && !output_tables) @@ -1650,6 +1680,49 @@ print_table_data_html(MYSQL_RES *result) } +static void +print_table_data_xml(MYSQL_RES *result) +{ + MYSQL_ROW cur; + MYSQL_FIELD *fields; + + mysql_field_seek(result,0); + + char *statement; + statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME)); + xmlencode(statement, (char*) glob_buffer.ptr()); + + (void) my_chomp(strend(statement)); + + tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement); + + my_free(statement,MYF(MY_ALLOW_ZERO_PTR)); + + fields = mysql_fetch_fields(result); + + while ((cur = mysql_fetch_row(result))) + { + (void) tee_fputs("\n <row>\n", PAGER); + for (uint i=0; i < mysql_num_fields(result); i++) + { + char *data; + ulong *lengths=mysql_fetch_lengths(result); + data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME)); + tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + xmlencode(data, cur[i]); + safe_put_field(data, strlen(data)); + tee_fprintf(PAGER, "</%s>\n", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + my_free(data,MYF(MY_ALLOW_ZERO_PTR)); + } + (void) tee_fputs(" </row>\n", PAGER); + } + (void) tee_fputs("</resultset>\n", PAGER); +} + static void print_table_data_vertically(MYSQL_RES *result) @@ -1681,6 +1754,45 @@ print_table_data_vertically(MYSQL_RES *result) } } +static const char +*array_value(const char **array, char *key) { + int x; + for(x=0; array[x]; x+=2) + if(!strcmp(array[x], key)) + return array[x+1]; + return 0; +} + +static void +xmlencode(char *dest, char *src) +{ + char *p = src; + const char *t; + char s[2] = { 0, 0 }; + *dest = 0; + + do + { + s[0] = *p; + if (!(t=array_value(xmlmeta, s))) + t = s; + dest=strmov(dest, t); + } while(*p++); +} + +static void +my_chomp(char *end) { + char *mend; + mend = end; + + do { + if (isspace(*mend)) { + *mend = '\0'; + } else + mend--; + } while (mend && *mend); +} + static void safe_put_field(const char *pos,ulong length) @@ -1711,7 +1823,7 @@ safe_put_field(const char *pos,ulong length) tee_fputs("\\n", PAGER); // This too else if (*pos == '\\') tee_fputs("\\\\", PAGER); - else + else tee_putc(*pos, PAGER); } } @@ -2096,6 +2208,9 @@ sql_real_connect(char *host,char *database,char *user,char *password, mysql_close(&mysql); connected= 0; } + else + mysql_ssl_clear(&mysql); /* SSL data structres should be freed + even if connection was not made */ mysql_init(&mysql); if (opt_connect_timeout) { diff --git a/client/mysqldump.c b/client/mysqldump.c index 597a1393f69..9d8e15a7942 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -274,12 +274,12 @@ puts("\ static void write_heder(FILE *sql_file, char *db_name) { - fprintf(sql_file, "# MySQL dump %s\n#\n", DUMP_VERSION); - fprintf(sql_file, "# Host: %s Database: %s\n", + fprintf(sql_file, "-- MySQL dump %s\n#\n", DUMP_VERSION); + fprintf(sql_file, "-- Host: %s Database: %s\n", current_host ? current_host : "localhost", db_name ? db_name : ""); - fputs("#--------------------------------------------------------\n", + fputs("---------------------------------------------------------\n", sql_file); - fprintf(sql_file, "# Server version\t%s\n", + fprintf(sql_file, "-- Server version\t%s\n", mysql_get_server_info(&mysql_connection)); return; } /* write_heder */ @@ -515,7 +515,7 @@ static int dbConnect(char *host, char *user,char *passwd) DBUG_ENTER("dbConnect"); if (verbose) { - fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost"); + fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost"); } mysql_init(&mysql_connection); if (opt_compress) @@ -542,7 +542,7 @@ static int dbConnect(char *host, char *user,char *passwd) static void dbDisconnect(char *host) { if (verbose) - fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost"); + fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost"); mysql_close(sock); } /* dbDisconnect */ @@ -608,7 +608,7 @@ static uint getTableStructure(char *table, char* db) delayed= opt_delayed ? " DELAYED " : ""; if (verbose) - fprintf(stderr, "# Retrieving table structure for table %s...\n", table); + fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", opt_quoted); table_name=quote_name(table,table_buff); @@ -837,7 +837,7 @@ static uint getTableStructure(char *table, char* db) { /* If old MySQL version */ if (verbose) fprintf(stderr, - "# Warning: Couldn't get status information for table '%s' (%s)\n", + "-- Warning: Couldn't get status information for table '%s' (%s)\n", table,mysql_error(sock)); } } @@ -934,7 +934,7 @@ static void dumpTable(uint numFields, char *table) ulong rownr, row_break, total_length, init_length; if (verbose) - fprintf(stderr, "# Sending SELECT query...\n"); + fprintf(stderr, "-- Sending SELECT query...\n"); if (path) { char filename[FN_REFLEN], tmp_path[FN_REFLEN]; @@ -977,11 +977,10 @@ static void dumpTable(uint numFields, char *table) sprintf(query, "SELECT * FROM %s", quote_name(table,table_buff)); if (where) { - fprintf(md_result_file,"# WHERE: %s\n",where); + fprintf(md_result_file,"-- WHERE: %s\n",where); strxmov(strend(query), " WHERE ",where,NullS); } - fputs("#\n\n", md_result_file); - + fputs("\n\n", md_result_file); if (mysql_query(sock, query)) { DBerror(sock, "when retrieving data from server"); @@ -997,7 +996,7 @@ static void dumpTable(uint numFields, char *table) return; } if (verbose) - fprintf(stderr, "# Retrieving rows...\n"); + fprintf(stderr, "-- Retrieving rows...\n"); if (mysql_num_fields(res) != numFields) { fprintf(stderr,"%s: Error in field count for table: '%s' ! Aborting.\n", diff --git a/client/mysqltest.c b/client/mysqltest.c index 7d149fe6f66..f269dd373c6 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -257,7 +257,6 @@ static int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { retur static int mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif - static void do_eval(DYNAMIC_STRING* query_eval, const char* query) { const char* p; @@ -1112,6 +1111,25 @@ char* safe_get_param(char* str, char** arg, const char* msg) DBUG_RETURN(str); } +int safe_connect(MYSQL* con, const char* host, const char* user, + const char* pass, + const char* db, int port, const char* sock) +{ + int con_error = 1; + int i; + for (i = 0; i < MAX_CON_TRIES; ++i) + { + if(mysql_real_connect(con, host,user, pass, + db, port, sock, 0)) + { + con_error = 0; + break; + } + sleep(CON_RETRY_SLEEP); + } + return con_error; +} + int do_connect(struct st_query* q) { @@ -1120,7 +1138,7 @@ int do_connect(struct st_query* q) char* p=q->first_argument; char buff[FN_REFLEN]; int con_port; - int i, con_error; + int con_error; DBUG_ENTER("do_connect"); DBUG_PRINT("enter",("connect: %s",p)); @@ -1153,20 +1171,9 @@ int do_connect(struct st_query* q) con_sock=fn_format(buff, con_sock, TMPDIR, "",0); if (!con_db[0]) con_db=db; - con_error = 1; - for (i = 0; i < MAX_CON_TRIES; ++i) - { - if(mysql_real_connect(&next_con->mysql, con_host, + if((con_error = safe_connect(&next_con->mysql, con_host, con_user, con_pass, - con_db, con_port, con_sock, 0)) - { - con_error = 0; - break; - } - sleep(CON_RETRY_SLEEP); - } - - if(con_error) + con_db, con_port, con_sock))) die("Could not open connection '%s': %s", con_name, mysql_error(&next_con->mysql)); @@ -1966,9 +1973,8 @@ int main(int argc, char** argv) if (!cur_con->name) die("Out of memory"); - if (!mysql_real_connect(&cur_con->mysql, host, - user, pass, db, port, unix_sock, - 0)) + if (safe_connect(&cur_con->mysql, host, + user, pass, db, port, unix_sock)) die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql)); while (!read_query(&q)) diff --git a/client/thread_test.c b/client/thread_test.c index dbe2acee8db..41adb23c408 100644 --- a/client/thread_test.c +++ b/client/thread_test.c @@ -19,7 +19,7 @@ #ifndef THREAD -int main(void) +int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { printf("This test must be compiled with multithread support to work\n"); exit(1); diff --git a/client/violite.c b/client/violite.c deleted file mode 100644 index 224ba051d82..00000000000 --- a/client/violite.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA */ - -#include <global.h> - -#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */ - -#include <errno.h> -#include <assert.h> -#include <violite.h> -#include <my_sys.h> -#include <my_net.h> -#include <m_string.h> - -#if defined(__EMX__) -#include <sys/ioctl.h> -#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C))) -#undef HAVE_FCNTL -#endif /* defined(__EMX__) */ - -#if defined(MSDOS) || defined(__WIN__) -#ifdef __WIN__ -#undef errno -#undef EINTR -#undef EAGAIN -#define errno WSAGetLastError() -#define EINTR WSAEINTR -#define EAGAIN WSAEINPROGRESS -#endif /* __WIN__ */ -#define O_NONBLOCK 1 /* For emulation of fcntl() */
-#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK EAGAIN -#endif - -#ifndef __WIN__ -#define HANDLE void * -#endif - -struct st_vio -{ - my_socket sd; /* my_socket - real or imaginary */ - HANDLE hPipe; - my_bool localhost; /* Are we from localhost? */ - int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ - my_bool fcntl_set; /* Have we done any fcntl yet?*/ - struct sockaddr_in local; /* Local internet address */ - struct sockaddr_in remote; /* Remote internet address */ - enum enum_vio_type type; /* Type of connection */ - char desc[30]; /* String description */ -}; - -typedef void *vio_ptr; -typedef char *vio_cstring; - -/* - * Helper to fill most of the Vio* with defaults. - */ - -static void vio_reset(Vio* vio, enum enum_vio_type type, - my_socket sd, HANDLE hPipe, - my_bool localhost) -{ - bzero((char*) vio, sizeof(*vio)); - vio->type = type; - vio->sd = sd; - vio->hPipe = hPipe; - vio->localhost= localhost; -} - -Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) -{ - Vio *vio; - DBUG_ENTER("vio_new"); - DBUG_PRINT("enter", ("sd=%d", sd)); - if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) - { - vio_reset(vio, type, sd, 0, localhost); - sprintf(vio->desc, "socket (%d)", vio->sd); - } - DBUG_RETURN(vio); -} - - -#ifdef __WIN__ - -Vio *vio_new_win32pipe(HANDLE hPipe) -{ - Vio *vio; - DBUG_ENTER("vio_new_handle"); - if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) - { - vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE); - strmov(vio->desc, "named pipe"); - } - DBUG_RETURN(vio); -} - -#endif - -void vio_delete(Vio * vio) -{ - /* It must be safe to delete null pointers. */ - /* This matches the semantics of C++'s delete operator. */ - if (vio) - { - vio_close(vio); - my_free((gptr) vio,MYF(0)); - } -} - -int vio_errno(Vio *vio) -{ - return errno; /* On Win32 this mapped to WSAGetLastError() */ -} - - -int vio_read(Vio * vio, gptr buf, int size) -{ - int r; - DBUG_ENTER("vio_read"); - DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size)); - assert(vio->sd >= 0); -#ifdef __WIN__ - if (vio->type == VIO_TYPE_NAMEDPIPE) - { - DWORD length;
- if (!ReadFile(vio->hPipe, buf, size, &length, NULL)) - DBUG_RETURN(-1); - DBUG_RETURN(length); - } - r = recv(vio->sd, buf, size,0); -#else - errno=0; /* For linux */ - r = read(vio->sd, buf, size); -#endif /* __WIN__ */ -#ifndef DBUG_OFF - if (r < 0) - { - DBUG_PRINT("error", ("Got error %d during read",errno)); - } -#endif /* DBUG_OFF */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - - -int vio_write(Vio * vio, const gptr buf, int size) -{ - int r; - DBUG_ENTER("vio_write"); - DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size)); - assert(vio->sd >= 0); -#ifdef __WIN__ - if ( vio->type == VIO_TYPE_NAMEDPIPE) - { - DWORD length;
- if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL)) - DBUG_RETURN(-1); - DBUG_RETURN(length); - } - r = send(vio->sd, buf, size,0); -#else - r = write(vio->sd, buf, size); -#endif /* __WIN__ */ -#ifndef DBUG_OFF - if (r < 0) - { - DBUG_PRINT("error", ("Got error on write: %d",errno)); - } -#endif /* DBUG_OFF */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - - -int vio_blocking(Vio * vio, my_bool set_blocking_mode) -{ - int r=0; - DBUG_ENTER("vio_blocking"); - DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode)); - -#if !defined(___WIN__) && !defined(__EMX__) -#if !defined(NO_FCNTL_NONBLOCK) - - if (vio->sd >= 0) - { - int old_fcntl=vio->fcntl_mode; - if (!vio->fcntl_set) - { - vio->fcntl_set = TRUE; - old_fcntl=vio->fcntl_mode = fcntl(vio->sd, F_GETFL); - } - if (set_blocking_mode) - vio->fcntl_mode &= ~O_NONBLOCK; /*clear bit */ - else - vio->fcntl_mode |= O_NONBLOCK; /*set bit */ - if (old_fcntl != vio->fcntl_mode) - r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode); - } -#endif /* !defined(NO_FCNTL_NONBLOCK) */ -#else /* !defined(__WIN__) && !defined(__EMX__) */ -#ifndef __EMX__ - if (vio->type != VIO_TYPE_NAMEDPIPE) -#endif - { - ulong arg; - int old_fcntl=vio->fcntl_mode; - if (!vio->fcntl_set) - { - vio->fcntl_set = TRUE; - old_fnctl=vio->fcntl_mode=0; - } - if (set_blocking_mode) - { - arg = 0; - vio->fcntl_mode &= ~O_NONBLOCK; /*clear bit */ - } - else - { - arg = 1; - vio->fcntl_mode |= O_NONBLOCK; /*set bit */ - } - if (old_fcntl != vio->fcntl_mode) - r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg)); - } -#endif /* !defined(__WIN__) && !defined(__EMX__) */ - DBUG_RETURN(r); -} - -my_bool -vio_is_blocking(Vio * vio) -{ - my_bool r; - DBUG_ENTER("vio_is_blocking"); - r = !(vio->fcntl_mode & O_NONBLOCK); - DBUG_PRINT("exit", ("%d", (int) r)); - DBUG_RETURN(r); -} - - -int vio_fastsend(Vio * vio, my_bool onoff) -{ - int r=0; - DBUG_ENTER("vio_fastsend"); - DBUG_PRINT("enter", ("onoff:%d", (int) onoff)); - assert(vio->sd >= 0); - -#ifdef IPTOS_THROUGHPUT - { -#ifndef __EMX__ - int tos = IPTOS_THROUGHPUT; - if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos))) -#endif /* !__EMX__ */ - { - int nodelay = 1; - if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay, - sizeof(nodelay))) { - DBUG_PRINT("warning", - ("Couldn't set socket option for fast send")); - r= -1; - } - } - } -#endif /* IPTOS_THROUGHPUT */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - -int vio_keepalive(Vio* vio, my_bool set_keep_alive) -{ - int r=0; - uint opt = 0; - DBUG_ENTER("vio_keepalive"); - DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int) - set_keep_alive)); - if (vio->type != VIO_TYPE_NAMEDPIPE) - { - assert(vio->sd >= 0); - if (set_keep_alive) - opt = 1; - r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, - sizeof(opt)); - } - DBUG_RETURN(r); -} - - -my_bool -vio_should_retry(Vio * vio) -{ - int en = errno; - return en == EAGAIN || en == EINTR || en == EWOULDBLOCK; -} - - -int vio_close(Vio * vio) -{ - int r; - DBUG_ENTER("vio_close"); - assert(vio->sd >= 0); /* Vill also work on PIPE:s */ -#ifdef __WIN__ - if (vio->type == VIO_TYPE_NAMEDPIPE) - { -#if defined(__NT__) && defined(MYSQL_SERVER) - CancelIO(vio->hPipe); - DisconnectNamedPipe(vio->hPipe); -#endif - r=CloseHandle(vio->hPipe); - } - else -#endif /* __WIN__ */ - { - r=0; - if (shutdown(vio->sd,2)) - r= -1; - if (closesocket(vio->sd)) - r= -1; - } - if (r) - { - DBUG_PRINT("error", ("close() failed, error: %d",errno)); - /* FIXME: error handling (not critical for MySQL) */ - } - vio_reset(vio,VIO_CLOSED,-1,0,TRUE); /* For debugging */ - DBUG_RETURN(r); -} - - -const char *vio_description(Vio * vio) -{ - return vio->desc; -} - -enum enum_vio_type vio_type(Vio* vio) -{ - return vio->type; -} - -my_socket vio_fd(Vio* vio) -{ - return vio->sd; -} - - -my_bool vio_peer_addr(Vio * vio, char *buf) -{ - DBUG_ENTER("vio_peer_addr"); - DBUG_PRINT("enter", ("sd=%d", vio->sd)); - if (vio->localhost) - { - strmov(buf,"127.0.0.1"); - } - else - { - size_socket addrLen = sizeof(struct sockaddr); - if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)), - &addrLen) != 0) - { - DBUG_PRINT("exit", ("getpeername, error: %d", errno)); - DBUG_RETURN(1); - } - my_inet_ntoa(vio->remote.sin_addr,buf); - } - DBUG_PRINT("exit", ("addr=%s", buf)); - DBUG_RETURN(0); -} - - -void vio_in_addr(Vio *vio, struct in_addr *in) -{ - DBUG_ENTER("vio_in_addr"); - if (vio->localhost) - bzero((char*) in, sizeof(*in)); /* This should never be executed */ - else - *in=vio->remote.sin_addr; - DBUG_VOID_RETURN; -} - -#endif /* HAVE_VIO */ diff --git a/configure.in b/configure.in index ddf2aa396e3..35007f502db 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 3.23.42) +AM_INIT_AUTOMAKE(mysql, 4.0.0-alpha) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -188,7 +188,7 @@ AC_DEFUN(AC_SYS_COMPILER_FLAG, [ CFLAGS="[$]OLD_CFLAGS $1" AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no) - ]) + ]) CFLAGS="[$]OLD_CFLAGS" @@ -681,6 +681,39 @@ int main() if test -z "$atom_ops"; then atom_ops="no"; fi AC_MSG_RESULT($atom_ops) + + AC_ARG_WITH(pstack, + [ --without-pstack Don't use the pstack backtrace library], + [USE_PSTACK=$withval], + [USE_PSTACK=yes]) + pstack_libs= pstack_dirs= + if test "$USE_PSTACK" = yes -a "$IS_LINUX" = "true" -a "$MACHINE_TYPE" = "i386" + then + have_libiberty= have_libbfd= + my_save_LIBS="$LIBS" +dnl I have no idea if this is a good test - can't find docs for libiberty + AC_CHECK_LIB([iberty], [fdmatch], + [have_libiberty=yes + AC_CHECK_LIB([bfd], [bfd_openr], [have_libbfd=yes], , [-liberty])]) + LIBS="$my_save_LIBS" + + AC_MSG_CHECKING([for pstack libs]) + if test x"$have_libiberty" = xyes -a x"$have_libbfd" = xyes + then + pstack_dirs='$(top_srcdir)'/pstack + pstack_libs="$pstack_dirs/libpstack.a -lbfd -liberty" + AC_SUBST([pstack_dirs]) + AC_SUBST([pstack_libs]) + AC_DEFINE([USE_PSTACK]) + AC_MSG_RESULT([yes]) +dnl This check isn't needed, but might be nice to give some feedback.... +dnl AC_CHECK_HEADER(libiberty.h, +dnl have_libiberty_h=yes, +dnl have_libiberty_h=no) + else + AC_MSG_RESULT([no (missing libbfd)]) + fi + fi fi # Check for gtty if termio.h doesn't exists @@ -1106,11 +1139,14 @@ then fi fi +TOOLS_LIBS="$NON_THREADED_CLIENT_LIBS" + # Should we use named pthread library ? AC_MSG_CHECKING("named thread libs:") if test "$with_named_thread" != "no" then LIBS="$with_named_thread $LIBS $with_named_thread" + TOOLS_LIBS="$with_named_thread $TOOLS_LIBS $with_named_thread" with_posix_threads="yes" with_mit_threads="no" AC_MSG_RESULT("$with_named_thread") @@ -1129,7 +1165,9 @@ else then AC_MSG_CHECKING("for pthread_create in -lpthread"); ac_save_LIBS="$LIBS" + ac_save_TOOLS_LIBS="$TOOLS_LIBS" LIBS="$LIBS -lpthread" + TOOLS_LIBS="$TOOLS_LIBS -lpthread" AC_TRY_LINK( [#include <pthread.h>], [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ], @@ -1138,6 +1176,7 @@ else if test "$with_posix_threads" = "no" then LIBS=" $ac_save_LIBS -lpthreads" + TOOLS_LIBS=" $ac_save_TOOLS_LIBS -lpthreads" AC_MSG_CHECKING("for pthread_create in -lpthreads"); AC_TRY_LINK( [#include <pthread.h>], @@ -1148,6 +1187,7 @@ else then # This is for FreeBSD LIBS="$ac_save_LIBS -pthread" + TOOLS_LIBS="$ac_save_TOOLS_LIBS -pthread" AC_MSG_CHECKING("for pthread_create in -pthread"); AC_TRY_LINK( [#include <pthread.h>], @@ -1158,6 +1198,7 @@ else then with_mit_threads="yes" LIBS="$ac_save_LIBS" + TOOLS_LIBS="$ac_save_TOOLS_LIBS" fi fi fi @@ -1682,6 +1723,45 @@ AC_ARG_WITH(server, [with_server=yes] ) +AC_ARG_WITH(embedded-server, + [ --with-embedded-server Build the embedded server (libmysqld).], + [with_embedded_server=$withval], + [with_embedded_server=no] +) + +AC_ARG_WITH(extra-tools, + [ --without-extra-tools Skip building utilites in the tools \ + directory.], + [with_tools=$withval], + [with_tools=yes] +) + +if test "$with_tools" = "yes" +then + tools_dirs="tools" +else + tools_dirs="" +fi +AC_SUBST(tools_dirs) + +MYSQL_CHECK_CPU +MYSQL_CHECK_MYSQLFS +MYSQL_CHECK_VIO +MYSQL_CHECK_OPENSSL + +libmysqld_dirs= +if test "$with_embedded_server" = "yes" +then + libmysqld_dirs=libmysqld + # We can't build embedded library without building the server, because + # we depend on libmysys, libmystrings, libmyisam, etc. + with_server=yes +fi +# XXX: We need to add @libmysqld_extra_libs@ (or whatever) so that +# mysql_config --libmysqld-libs will print out something like +# -L/path/to/lib/mysql -lmysqld -lmyisam -lmysys -lmystrings -ldbug ... +AC_SUBST([libmysqld_dirs]) + # Shall we build the docs? AC_ARG_WITH(docs, [ --without-docs Skip building of the documentation.], @@ -1732,23 +1812,23 @@ fi AC_SUBST(readline_dir) AC_SUBST(readline_link) -# Choose a character set -dnl in order to add new charset, you must add charset name to -dnl CHARSETS_AVAILABLE list and add the charset name to -dnl sql/share/charsets/Index. If the character set uses strcoll -dnl or other special handling, you must also create -dnl strings/ctype-$charset_name.c +dnl In order to add new charset, you must add charset name to +dnl this CHARSETS_AVAILABLE list and sql/share/charsets/Index. +dnl If the character set uses strcoll or other special handling, +dnl you must also create strings/ctype-$charset_name.c -CHARSETS_AVAILABLE="big5 cp1251 cp1257 croat czech danish dec8 dos estonia euc_kr gb2312 gbk german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr latin1 latin2 latin5 swe7 usa7 win1250 win1251 win1251ukr ujis sjis tis620" +AC_DIVERT_PUSH(0) +CHARSETS_AVAILABLE="big5 cp1251 cp1257 + croat czech danish dec8 dos estonia euc_kr gb2312 gbk + german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr + latin1 latin1_de latin2 latin5 sjis swe7 tis620 ujis + usa7 win1250 win1251ukr" +CHARSETS_DEPRECATED="win1251" DEFAULT_CHARSET=latin1 +AC_DIVERT_POP -dnl win1251 is deprecated - it's available, but not listed here in the help AC_ARG_WITH(charset, - [ --with-charset=CHARSET Use CHARSET by default (one of: big5 cp1251 cp1257 - croat czech danish dec8 dos estonia euc_kr gb2312 gbk - german1 greek hebrew hp8 hungarian koi8_ru koi8_ukr - latin1 latin2 latin5 swe7 usa7 win1250 win1251ukr - ujis sjis tis620; Default is latin1)], + [ --with-charset=CHARSET Use CHARSET by default (one of: $CHARSETS_AVAILABLE; Default is $DEFAULT_CHARSET)], [default_charset="$withval"], [default_charset="$DEFAULT_CHARSET"]) @@ -1769,7 +1849,7 @@ elif test "$extra_charsets" = complex; then CHARSETS=`echo $CHARSETS` # get rid of line breaks else if test "$extra_charsets" = all; then - CHARSETS="$CHARSETS_AVAILABLE" + CHARSETS="$CHARSETS_AVAILABLE $CHARSETS_DEPRECATED" else CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'` fi @@ -1790,7 +1870,7 @@ CHARSETS=$TMP_CHARSETS for cs in $CHARSETS do charset_okay=0 - for charset in $CHARSETS_AVAILABLE + for charset in $CHARSETS_AVAILABLE $CHARSETS_DEPRECATED do if test $cs = $charset; then charset_okay=1; fi done @@ -1994,20 +2074,16 @@ AC_SUBST(CLIENT_LIBS) AC_SUBST(sql_client_dirs) AC_SUBST(linked_client_targets) -if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no" -then - AC_DEFINE(THREAD) -fi - if test "$with_server" = "yes" then + AC_DEFINE(THREAD) # Avoid _PROGRAMS names THREAD_LPROGRAMS="test_thr_alarm test_thr_lock" AC_SUBST(THREAD_LPROGRAMS) THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o" AC_SUBST(THREAD_LOBJECTS) - sql_server_dirs="strings dbug mysys extra regex isam merge myisam myisammrg heap sql" - server_scripts="safe_mysqld mysql_install_db" + sql_server_dirs="strings dbug mysys extra regex isam merge myisam myisammrg heap vio sql" + server_scripts="mysqld_safe mysql_install_db" if test X"$have_berkeley_db" != Xno; then if test X"$have_berkeley_db" != Xyes; then # we must build berkeley db from source @@ -2096,10 +2172,7 @@ EOF AC_DEFINE(HAVE_GEMINI_DB) fi -fi -if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no" -then if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes" then # MIT user level threads @@ -2136,17 +2209,18 @@ AC_SUBST(server_scripts) # Some usefull subst AC_SUBST(CC) AC_SUBST(GXX) +AC_SUBST(TOOLS_LIBS) # Output results AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \ strings/Makefile regex/Makefile heap/Makefile \ bdb/Makefile \ myisam/Makefile myisammrg/Makefile \ - man/Makefile \ - readline/Makefile libmysql_r/Makefile libmysql/Makefile client/Makefile \ - sql/Makefile sql/share/Makefile \ + man/Makefile readline/Makefile vio/Makefile \ + libmysql_r/Makefile libmysqld/Makefile libmysql/Makefile client/Makefile \ + pstack/Makefile sql/Makefile sql/share/Makefile \ merge/Makefile dbug/Makefile scripts/Makefile \ - include/Makefile sql-bench/Makefile \ + include/Makefile sql-bench/Makefile tools/Makefile \ tests/Makefile Docs/Makefile support-files/Makefile \ mysql-test/Makefile \ include/mysql_version.h diff --git a/extra/resolveip.c b/extra/resolveip.c index d739f8de244..d6cfee9bb4c 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -29,6 +29,7 @@ #include <netdb.h> #include <m_ctype.h> #include <my_sys.h> +#include <m_string.h> #include <getopt.h> #if !defined(_AIX) && !defined(HAVE_UNIXWARE7_THREADS) && !defined(HAVE_UNIXWARE7_POSIX) && !defined(h_errno) diff --git a/fs/CorbaFS.idl b/fs/CorbaFS.idl new file mode 100644 index 00000000000..8fe089bd13c --- /dev/null +++ b/fs/CorbaFS.idl @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------------- +// CorbaDS Module - Implement Kernel functionality in korbit +// ----------------------------------------------------------------------------- +// +// Main source of information: +// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html +// +module CorbaFS { + + struct dirent + { + long inode; // inode number + string name; // file name (null-terminated) + }; + + typedef sequence<dirent> DirEntSeq; + typedef sequence<octet> Buffer; + + interface Inode { + void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid, + out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks, + out long atime, out long mtime, out long ctime); + void readpage(out Buffer buffer, in long size, in long offset); + void release(); + }; + + interface FileSystem { + Inode getInode(in string path); + + // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT + // field of the mode value. + DirEntSeq readdir(in string path); + + // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT + // field of the mode value. + string readlink(in string filename); + }; +}; diff --git a/fs/Makefile.am b/fs/Makefile.am new file mode 100644 index 00000000000..33d1acd913d --- /dev/null +++ b/fs/Makefile.am @@ -0,0 +1,93 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# +# 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 + +#called from the top level Makefile + +CFLAGS = $(ORBIT_CFLAGS) -g +LFLAGS = $(ORBIT_LIBS) +orbit_idl = @orbit_idl@ +orbit_includes = @orbit_includes@ +orbit_libs = @orbit_libs@ + +DISTCLEANFILES = CorbaFS-common.* CorbaFS-stubs.* CorbaFS-skels.* CorbaFS.h + +MYSQLDATAdir = $(localstatedir) +MYSQLSHAREdir = $(pkgdatadir) +MYSQLBASEdir= $(prefix) +INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include \ + -I$(srcdir)/../regex \ + -I$(srcdir) -I../include -I.. -I. \ + -I$(srcdir) -I../include -I.. -I. \ + $(orbit_includes) +WRAPLIBS= @WRAPLIBS@ +libexec_PROGRAMS = mysqlcorbafsd +noinst_PROGRAMS =mysqlfs_test +LDADD = ../libmysql/libmysqlclient.la $(orbit_libs) +mysqlcorbafsd_LDADD = $(LDADD) $(CXXLDFLAGS) +noinst_HEADERS = +mysqlfs_test_SOURCES = mysqlcorbafs_test.c CorbaFS-common.c CorbaFS-stubs.c libmysqlfs.c +mysqlcorbafsd_SOURCES = mysqlcorbafs.c CorbaFS-skels.c database.c CorbaFS-common.c libmysqlfs.c + +DEFS = -DMYSQL_SERVER \ + -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \ + -DDATADIR="\"$(MYSQLDATAdir)\"" \ + -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ + @DEFS@ +# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion +BUILT_SOURCES = CorbaFS-common.c CorbaFS-stubs.c CorbaFS-skels.c CorbaFS.h +EXTRA_DIST = $(BUILT_SOURCES) +#YFLAGS = -d + +OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\ + __math.h time.h __time.h unistd.h __unistd.h types.h \ + xtypes.h ac-types.h posix.h string.h __string.h \ + errno.h socket.h inet.h dirent.h netdb.h \ + cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \ + prio_queue.h pthread_attr.h pthread_once.h queue.h\ + sleep.h specific.h version.h pwd.h timers.h uio.h \ + cdefs.h machdep.h signal.h __signal.h util.h lex.h \ + wait.h + +link_sources: + rm -f mini_client_errors.c + @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c + + +# Don't update the files from bitkeeper +%::SCCS/s.% + +idltargets : CorbaFS.idl + $(ORBIT_IDL) CorbaFS.idl + $(orbit_idl) CorbaFS.idl + +# individual rules + +CorbaFS-stubs.c : CorbaFS.idl + $(orbit_idl) CorbaFS.idl + +CorbaFS-common.c : CorbaFS.idl + $(orbit_idl) CorbaFS.idl + +CorbaFS-skels.c : CorbaFS.idl + $(orbit_idl) CorbaFS.idl + +#CorbaFS-client.c : CorbaFS.h + +#CorbaFS-server.c : CorbaFS.h + +CorbaFS.h : CorbaFS.idl + $(orbit_idl) CorbaFS.idl + diff --git a/fs/README b/fs/README new file mode 100644 index 00000000000..5d86da3a7e4 --- /dev/null +++ b/fs/README @@ -0,0 +1,58 @@ +MySQL Filesystem +Tõnu Samuel - tonu@mysql.com +Some additional information is available on http://no.spam.ee/~tonu/mysqlfs.html + +WARNING: Experimental code and known to crash computer. + +Instructions, how to get this stuff working: +1. Make sure you have ORBit, includeing development libraries installed. They should be version 0.5.3 or later. +- I am lazy man and use default ones included with my RedHat: + [root@localhost /root]# rpm -qa | grep ORBit + ORBit-0.5.3-2 + ORBit-devel-0.5.3-2 + [root@localhost /root]# + +2. Prepare kernel to include korbit: +- Get Linux 2.4.1 kernel source. (very possibly this patch works on 2.4.0 without modifications too) +- unpack it +- apply patch named "korbit-kernel-2.4.1-patch" on it. +- make menuconfig +- In section "Networking options": + ... + [*] Kernel ORB (EXPERIMENTAL) + ... + <M> CORBA User-space FileSystem (EXPERIMENTAL) + ... +- make dep ; make bzlilo ; make modules ; make modules_install +- reboot +- Execute: insmod /lib/modules/$(uname -r)/kernel/net/korbit/modules/CorbaFS/client/corba-corbafs-client.o + You should see "gethostname() = localhost". Look at known bug 3 in the end of this doc. + +3. Make sure MySQL server is working on your system +- On my RedHat 7.0 I execute "/etc/init.d/mysqld start" + +4. Prepare MySQL FS daemon +- Get MySQL 4.0 from repository OR get MySQL FS source from http://no.spam.ee/~tonu/mysqlfs.html +- unpack it. In MySQL 4.0 source this is located in directory named "fs". cd into it. +- make +- Execute command "./RunServer" + +5. mount MySQL server to disk tree +- Execute command "mkdir /mnt/mysql" +- Execute command "mount -t corbafs -o `cat /tmp/mysqlcorbafs.ior` none /mnt/mysql/" +- Check you SQL server content by executing "ls -la /mnt/mysql/" + +Known bugs: + +1. User bugs. fix user ;) + +2. MySQL FS daemon will crash or will be stopped when cobrafs is mounted, then there is no way +to unmount disks anymore. This is korbit business to handle such cases and I had no time to dig +into korbit code. + +3. host name returned by gethostname() should be "localhost" or korbit will crash. Also "localhost" +must be first string after 127.0.0.1 in /etc/hosts + + + + diff --git a/fs/RunServer.sh b/fs/RunServer.sh new file mode 100755 index 00000000000..22d152bb20b --- /dev/null +++ b/fs/RunServer.sh @@ -0,0 +1,2 @@ +.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 --debug='d:t:o,~/mysqlfsd.trace' $* +#.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 $* diff --git a/fs/database.c b/fs/database.c new file mode 100644 index 00000000000..2e93f87376a --- /dev/null +++ b/fs/database.c @@ -0,0 +1,629 @@ +/* Copyright (C) 2000 db AB & db Finland AB & TCX DataKonsult AB + * + * 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 + */ + +/* + * Database functions + * + * Using these functions we emulate filesystem behaviour on top of SQL + * database. + * Written by Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> + * + * FIXME: + * - Direct handling of database handlers without SQL parsing overhead + * - connection pool + * - configurable function name/file name mappings + */ + + +#include "libmysqlfs.h" +#include "mysqlcorbafs.h" +#include <unistd.h> +#include <string.h> +#include <my_sys.h> + +DYNAMIC_ARRAY field_array; + +/* + * ** dbConnect -- connects to the host and selects DB. + * ** Also checks whether the tablename is a valid table name. + * */ +int db_connect(char *host, char *user,char *passwd) +{ + DBUG_ENTER("db_connect"); + DBUG_PRINT("enter",("host: '%s', user: '%s', passwd: '%s'", host, user, passwd)); + + if (verbose) + { + fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost"); + } + mysql_init(&connection); + if (opt_compress) + mysql_options(&connection,MYSQL_OPT_COMPRESS,NullS); +#ifdef HAVE_OPENSSL + if (opt_use_ssl) + mysql_ssl_set(&connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, + opt_ssl_capath); +#endif + if (!(sock= mysql_real_connect(&connection,host,user,passwd, + NULL,opt_mysql_port,opt_mysql_unix_port,0))) + { + DBerror(&connection, "when trying to connect"); + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} /* dbConnect */ + + +/* + * ** dbDisconnect -- disconnects from the host. + * */ +void db_disconnect(char *host) +{ + DBUG_ENTER("db_disconnect"); + DBUG_PRINT("enter",("host: '%s'", host)); + if (verbose) + fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost"); + mysql_close(sock); + DBUG_VOID_RETURN; +} /* dbDisconnect */ + +#define OUTPUT(x) strcpy(buffptr,x); buffptr+=strlen(x); +#define OUTPUT_TOP(x) strcpy(topptr,x); topptr+=strlen(x); +#define OUTPUT_MIDDLE(x) strcpy(midptr,x); midptr+=strlen(x); +#define OUTPUT_BOTTOM(x) strcpy(botptr,x); botptr+=strlen(x); +#define OUTPUT_HEADER(x) strcpy(hdrptr,x); hdrptr+=strlen(x); + +void db_show_result(MYSQL* sock, char *b, struct format *f) +{ + MYSQL_ROW row; + MYSQL_RES *result; + MYSQL_FIELD *field; + char *buffptr; + char topseparator[BUFLEN]=""; + char middleseparator[BUFLEN]=""; + char bottomseparator[BUFLEN]=""; + char header[BUFLEN]=""; + char *topptr=topseparator; + char *midptr=middleseparator; + char *botptr=bottomseparator; + char *hdrptr=header; + uint i,count, length; + + DBUG_ENTER("db_show_result"); + DBUG_PRINT("enter",("b: '%s', f '%x'", b, f)); + + result=mysql_store_result(sock); + + buffptr=b; + OUTPUT(f->tablestart) + + OUTPUT_TOP(f->leftuppercorner); + OUTPUT_MIDDLE(f->leftcross); + OUTPUT_BOTTOM(f->leftdowncorner); + OUTPUT_HEADER(f->headerrowstart); + + + count=mysql_num_fields(result); +// while ((field = mysql_fetch_field(result))) + for(i=0 ; i < count ; ++i) + { + field = mysql_fetch_field(result); + length=(uint) strlen(field->name); + OUTPUT_HEADER(f->headercellstart); + + length=max(length,field->max_length); + if (length < 4 && !IS_NOT_NULL(field->flags)) + length=4; // Room for "NULL" + field->max_length=length; + + memset(topptr,'=',field->max_length); + memset(midptr,'-',field->max_length); + memset(botptr,'=',field->max_length); + + sprintf(hdrptr,"%-*s",field->max_length,field->name); + //num_flag[off]= IS_NUM(field->type); + + topptr+=field->max_length; + midptr+=field->max_length; + botptr+=field->max_length; + hdrptr+=field->max_length; + + if(i<count-1) { + OUTPUT_TOP(f->topcross); + OUTPUT_MIDDLE(f->middlecross); + OUTPUT_BOTTOM(f->bottomcross); + OUTPUT_HEADER(f->headercellseparator); + } + } + OUTPUT_TOP(f->rightuppercorner); + OUTPUT_MIDDLE(f->rightcross); + OUTPUT_BOTTOM(f->rightdowncorner); + + OUTPUT_HEADER(f->headercellend); + OUTPUT_HEADER(f->headerrowend); + + OUTPUT(topseparator); + OUTPUT(header); + OUTPUT(middleseparator); + while(row=mysql_fetch_row(result)) { + mysql_field_seek(result,0); + + OUTPUT(f->contentrowstart); + for(i=0 ; i < mysql_field_count(sock); ++i) { + field = mysql_fetch_field(result); + OUTPUT(f->contentcellstart); + sprintf(buffptr,"%-*s",field->max_length,row[i]); + buffptr+=field->max_length; + + if(i==mysql_field_count(sock)) + { + OUTPUT(f->contentcellend); + } else { + OUTPUT(f->contentcellseparator); + } + } + OUTPUT(f->contentrowend); + } + OUTPUT(bottomseparator); + OUTPUT(f->tableend); + + mysql_free_result(result); + DBUG_VOID_RETURN; +} + + +int db_function(char *b,const char *server, const char *database,const char *table,const char *field, const char *value, const char* path, struct func_st *function) +{ + char buff[BUFLEN]; + int i; + DBUG_ENTER("db_function"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s', path: '%s'", b, database, table, field,path)); + + if(*database) { + if (mysql_select_db(sock,database)) + { + printf("error when changing database to'%s'\n",database); + DBUG_RETURN(-1); + } + } + + sprintf(buff,"%s",function->function); + search_and_replace("$database",database,buff); + search_and_replace("$table",table,buff); + search_and_replace("$field",field,buff); + search_and_replace("$value",value,buff); + DBUG_PRINT("info",("path: '%s'",path)); + DBUG_PRINT("info",("sum: '%d'",(database[0] ? strlen(database)+1 : 0) +(table[0] ? strlen(table)+1 : 0) +(field[0] ? strlen(field)+1 : 0) +(value[0] ? strlen(value)+1 : 0) +1)); + search_and_replace("$*",path+ + (server[0] ? strlen(server)+1 : 0) + + (database[0] ? strlen(database)+1 : 0) + + (table[0] ? strlen(table)+1 : 0) + + (field[0] ? strlen(field)+1 : 0) + + (value[0] ? strlen(value)+1 : 0) + + function->length + + 1,buff); + DBUG_PRINT("info",("Executing constructed function query: '%s'", buff)); + if (mysql_query(sock, buff)) + { + printf("error when executing '%s'\n",buff); + sprintf(b,"ERROR %d: %s",mysql_error(sock),mysql_error(sock)); + DBUG_VOID_RETURN; + } + + db_show_result(sock, b, &Human); + DBUG_PRINT("info",("Returning: %s", b)); + DBUG_RETURN(1); +} + +int db_show_field(char *b,const char *database,const char *table, const char *field,const char *value, const char *param) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char buff[BUFLEN]; + int i=0; + my_string *ptr; + DBUG_ENTER("db_show_field"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s' value: '%s'", b, database, table, field, value)); + + /* We cant output fields when one of these variables is missing */ + if (!(database[0] && table[0] && field[0])) + DBUG_RETURN(-1); + + init_dynamic_array(&field_array, sizeof(buff), 4096, 1024); + + if (mysql_select_db(sock,database)) + { + printf("error when changing database to'%s'\n",database); + delete_dynamic(&field_array); + DBUG_RETURN(-1); + } + + if(param) { + sprintf(buff,"%s",param); + } else { + sprintf(buff,"select %s from %s where %s='%s' LIMIT 1",field,table,field,value); + } + if (mysql_query(sock, buff)) + { + printf("error when executing '%s'\n",buff); + delete_dynamic(&field_array); + DBUG_RETURN(-1); + } + + + db_show_result(sock,b,&Human); +/* if(result=mysql_use_result(sock)) { + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i][BUFLEN],row[0]); + DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN])); +// ptr = (*dynamic_element(&field_array,i,row[0])); + i++; + } + } +// fix_filenames((char *)b); + mysql_free_result(result); + */ + delete_dynamic(&field_array); + DBUG_RETURN(i); + +} +int db_show_fields(char *b,const char *database,const char *table) +{ + MYSQL_RES *result; + MYSQL_ROW row; + MYSQL_FIELD *field; + char buff[BUFLEN]; + int i=0; + + DBUG_ENTER("show_fields"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table)); + if (mysql_select_db(sock,database)) + { + printf("error when changing database to'%s'\n",database); + DBUG_RETURN(-1); + } + if(result=mysql_list_fields(sock,buff,NULL)) { + + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i*BUFLEN],row[0]); + DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN])); + i++; + } + } + mysql_free_result(result); + DBUG_RETURN(i); +} + +int db_show_primary_keys(char *b,const char *database, const char *table) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char buff[BUFLEN]; + char buff2[BUFLEN]; + unsigned int i; + + DBUG_ENTER("db_show_primary_keys"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table)); + if (mysql_select_db(sock,database)) + { + printf("error when changing database to '%s'\n",database); + DBUG_RETURN(-1); + } + sprintf(buff,"show keys from %s",table); + if (mysql_query(sock, buff)) + { + printf("error when executing '%s'\n",buff); + DBUG_RETURN(0); + } + buff2[0]='\0'; + if(result=mysql_use_result(sock)) { + while(row=mysql_fetch_row(result)) { + if(!strcasecmp(row[2],"PRIMARY")) { + strcat(buff2,row[4]); + strcat(buff2,",\"_\","); + } + } + buff2[strlen(buff2)-5]='\0'; + if(!buff2[0]) + DBUG_RETURN(-1); // No PRIMARY keys in table + DBUG_PRINT("info",("Keys: %s<- \n", buff2)); + } else + DBUG_RETURN(-1); // No keys in table + + sprintf(buff,"SELECT CONCAT(%s) AS X FROM %s LIMIT 256",buff2,table); + if (mysql_query(sock, buff)) + { + printf("error when executing '%s'\n",buff); + DBUG_RETURN(0); + } + i=0; + if(result=mysql_use_result(sock)) { + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i*BUFLEN],row[0]); + fix_filenames(&b[i*BUFLEN]); + DBUG_PRINT("info",("primarykey %s at %x, %i", &b[i*BUFLEN],&b[i*BUFLEN],i)); + if(i++ >= MAXDIRS) + break; + } + } + mysql_free_result(result); + DBUG_RETURN(i); +} + + +int db_show_keys(char *b,const char *database, const char *table) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char buff[BUFLEN]; + int i=0; + + DBUG_ENTER("show_keys"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table)); + if (mysql_select_db(sock,database)) + { + printf("error when changing database to'%s'\n",database); + DBUG_RETURN(-1); + } + sprintf(buff,"show keys from %s",table); + if (mysql_query(sock, buff)) + { + printf("error when executing '%s'\n",buff); + DBUG_RETURN(0); + } + if(result=mysql_use_result(sock)) { + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i*BUFLEN],row[0]); + DBUG_PRINT("info",("Key %s at %x", &b[i*BUFLEN],&b[i*BUFLEN])); + i++; + } + } + mysql_free_result(result); + DBUG_RETURN(i); +} + + +int db_show_tables(char *b,const char *database) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char buff[BUFLEN]; + int i=0; + + DBUG_ENTER("db_show_tables"); + DBUG_PRINT("enter",("buffer: '%s', database: '%s'", b, database)); + if (mysql_select_db(sock,database)) + { + printf("error when changing database to '%s'\n",database); + DBUG_RETURN(-1); + } + + if(result=mysql_list_tables(sock,NULL)) { + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i*BUFLEN],row[0]); + DBUG_PRINT("info",("table %s at %x", &b[i*BUFLEN],&b[i*BUFLEN])); + i++; + } + } + mysql_free_result(result); + DBUG_RETURN(i); +} + +/* + * Finds all servers we are connected to + * and stores them in array supplied. + * returns count of servers + */ +int +db_show_servers(char *b,int size) +{ + char* bufptr; + char* buff[BUFLEN*2]; + DBUG_ENTER("db_show_servers"); + DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size)); + bufptr=mysql_get_host_info(sock); + // FIXME: Actually we need to escape prohibited symbols in filenames + fix_filenames(bufptr); + strcpy(b,bufptr); + DBUG_RETURN(1); +} + +/* + * Finds all databases in server + * and stores them in array supplied. + * returns count of databases + */ +int +db_show_databases(char *b,int size) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char buff[BUFLEN]; + int i=0; + + DBUG_ENTER("db_show_databases"); + DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size)); + result=mysql_list_dbs(sock,NULL); + while(row=mysql_fetch_row(result)) + { + strcpy(&b[i*BUFLEN],row[0]); + DBUG_PRINT("info",("database %s at %x", &b[i*BUFLEN],&b[i*BUFLEN])); + i++; + } + mysql_free_result(result); + DBUG_RETURN(i); +} + +void db_load_formats() +{ + + /* In future we should read these variables + * from configuration file/database here */ + + /* HTML output */ + HTML.tablestart="<table>\n"; + + HTML.headerrowstart="<tr>"; + HTML.headercellstart="<th>"; + HTML.headercellseparator="</th><th>"; + HTML.headercellend="</th>"; + HTML.headerrowend="</tr>\n"; + HTML.headerformat=0; + + HTML.leftuppercorner=""; + HTML.rightuppercorner=""; + HTML.leftdowncorner=""; + HTML.rightdowncorner=""; + HTML.topcross=""; + HTML.middlecross=""; + HTML.bottomcross=""; + HTML.leftcross=""; + HTML.rightcross=""; + HTML.bottomcross=""; + + HTML.contentrowstart="<tr>"; + HTML.contentcellstart="<td>"; + HTML.contentcellseparator="</td><td>"; + HTML.contentcellend="</td>"; + HTML.contentrowend="</tr>\n"; + HTML.headerformat=0; + + HTML.footerrowstart=""; + HTML.footercellstart=""; + HTML.footercellseparator=""; + HTML.footercellend=""; + HTML.footerrowend="\n"; + HTML.footerformat=0; + + HTML.tableend="</table>\n"; + +/* Nice to look mysql client like output */ + + Human.tablestart="\n"; + + Human.headerrowstart="| "; + Human.headercellstart=""; + Human.headercellseparator=" | "; + Human.headercellend=" |"; + Human.headerrowend="\n"; + Human.headerformat=1; + + Human.leftuppercorner="/="; + Human.rightuppercorner="=\\\n"; + Human.leftdowncorner="\\="; + Human.rightdowncorner="=/\n"; + Human.leftcross="+-"; + Human.rightcross="-+\n"; + Human.topcross="=T="; + Human.middlecross="-+-"; + Human.bottomcross="=`="; + + Human.contentrowstart="| "; + Human.contentcellstart=""; + Human.contentcellseparator=" | "; + Human.contentcellend=" |"; + Human.contentrowend="\n"; + Human.contentformat=1; + + Human.footerrowstart=""; + Human.footercellstart=""; + Human.footercellseparator=""; + Human.footercellend=""; + Human.footerrowend="\n"; + Human.footerformat=1; + + Human.tableend="\n"; + +/* Comma-separated format. For machine reading */ + + /* XML */ + +/* + tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement); + (void) tee_fputs("\n <row>\n", PAGER); + data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME)); + tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + xmlencode(data, cur[i]); + tee_fprintf(PAGER, "</%s>\n", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + </row>\n" </resultset>\n*/ +} + +gptr db_load_functions() +{ + char *functions[]={ + "database",".tables","SHOW TABLES","0", + "table",".status","SHOW TABLE STATUS FROM $table","0", + "table",".count","SELECT COUNT(*) FROM $table","0", + "table",".table","SELECT * FROM $table","0", + "table",".check","CHECK TABLE $table","0", + "table",".repair","REPAIR TABLE $table","0", + "key",".min","SELECT MIN($key) FROM $table","0", + "key",".max","SELECT MAX($key) FROM $table","0", + "key",".avg","SELECT AVG($key) FROM $table","0", + "server",".uptime","SHOW STATUS like 'Uptime'","0", + "server",".version","SELECT VERSION()","0", + "server",".execute","$*","1", + "root",".connect","CONNECT $*","0", + NULL,NULL,NULL,NULL + }; + char buff[BUFLEN]; + int i=0; + struct func_st func; + DBUG_ENTER("db_load_functions"); + init_dynamic_array(&functions_array, sizeof(struct func_st), 4096, 1024); + while(functions[i]) { + strcpy(func.type_s, functions[i]); /* Type in string: "table"` */ + strcpy(func.filename, functions[i+1]); /* Name like it appears on FS: "count" */ + strcpy(func.function, functions[i+2]); /* Query: "SELECT COUNT(*) FROM `%table`" */ + func.continuous= atoi(functions[i+3]); /* Query: "If command can be continued" */ + + if(!strcasecmp(func.type_s,"server")) + func.type=SERVER_FUNCTION; + else if(!strcasecmp(func.type_s,"table")) + func.type=TABLE_FUNCTION; + else if(!strcasecmp(func.type_s,"key")) + func.type=KEY_FUNCTION; + else if(!strcasecmp(func.type_s,"database")) + func.type=DATABASE_FUNCTION; + else if(!strcasecmp(func.type_s,"field")) + func.type=FIELD_FUNCTION; + else if(!strcasecmp(func.type_s,"root")) + func.type=ROOT_FUNCTION; + else func.type=NONE_FUNCTION; + + func.length=strlen(func.filename); /* Filename length */ + DBUG_PRINT("info",("func.type_s: %s",func.type_s)); + DBUG_PRINT("info",("func.filename: %s",func.filename)); + DBUG_PRINT("info",("func.function: %s",func.function)); + DBUG_PRINT("info",("func.type: %d",func.type)); + DBUG_PRINT("info",("func.continuous: %d",func.continuous)); + DBUG_PRINT("info",("i: %d",i)); + insert_dynamic(&functions_array,(gptr)&func); + i+=4; + } + DBUG_RETURN((gptr)&functions_array); +} + diff --git a/fs/dump.sql b/fs/dump.sql new file mode 100644 index 00000000000..c61669cecb5 --- /dev/null +++ b/fs/dump.sql @@ -0,0 +1,28 @@ +# MySQL dump 8.12 +# +# Host: localhost Database: mysqlfs +#-------------------------------------------------------- +# Server version 3.23.33 + +# +# Table structure for table 'functions' +# + +CREATE TABLE functions ( + type enum('server','database','table','field','key') NOT NULL default 'server', + name char(20) NOT NULL default '', + sql char(128) NOT NULL default '', + PRIMARY KEY (type,name) +) TYPE=MyISAM; + +# +# Dumping data for table 'functions' +# + +INSERT INTO functions VALUES ('server','uptime','SHOW STATUS like \'Uptime\''); +INSERT INTO functions VALUES ('server','version','SELECT VERSION()'); +INSERT INTO functions VALUES ('table','count','SELECT COUNT(*) FROM `%table`'); +INSERT INTO functions VALUES ('key','min','SELECT MIN(%key) FROM `%table`'); +INSERT INTO functions VALUES ('key','max','SELECT MAX(%key) FROM `%table`'); +INSERT INTO functions VALUES ('key','avg','SELECT AVG(%key) FROM `%table`'); + diff --git a/fs/korbit-kernel-2.4.1-patch b/fs/korbit-kernel-2.4.1-patch new file mode 100644 index 00000000000..d97b1dac344 --- /dev/null +++ b/fs/korbit-kernel-2.4.1-patch @@ -0,0 +1,35661 @@ +diff -urN linux-2.4.1/.cvsignore linux-2.4.1-korbit/.cvsignore +--- linux-2.4.1/.cvsignore Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/.cvsignore Thu Feb 1 11:46:48 2001 +@@ -0,0 +1 @@ ++makekorbit.sh +diff -urN linux-2.4.1/KORBit.Announce linux-2.4.1-korbit/KORBit.Announce +--- linux-2.4.1/KORBit.Announce Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/KORBit.Announce Thu Feb 1 11:46:48 2001 +@@ -0,0 +1,62 @@ ++From sabre@nondot.org Fri Dec 8 15:15:43 2000 ++Date: Fri, 8 Dec 2000 17:10:47 -0600 (CST) ++From: Chris Lattner <sabre@nondot.org> ++To: linux-kernel@vger.kernel.org, orbit-list@gnome.org ++Cc: korbit-cvs@lists.sourceforge.net ++Subject: ANNOUNCE: Linux Kernel ORB: kORBit ++ ++ ++This email is here to announce the availability of a port of ORBit (the ++GNOME ORB) to the Linux kernel. This ORB, named kORBit, is available from ++our sourceforge web site (http://korbit.sourceforge.net/). A kernel ORB ++allows you to write kernel extensions in CORBA and have the kernel call ++into them, or to call into the kernel through CORBA. This opens the door ++to a wide range of experiments/hacks: ++ ++* We can now write device drivers in perl, and let them run on the iMAC ++ across the hall from you. :) ++* Through the use of a LD_PRELOAD'd syscall wrapper library, you can ++ forward system calls through CORBA to an arbitrary local/remote machine. ++* CORBA servers are implemented as Linux kernel modules, so they may be ++ dynamically loaded or unloaded from a running system at any time. CORBA ++ servers expose their IOR's through a /proc/corba filesystem. ++* Filesystems may be implemented as remote CORBA objects and mounted on ++ the local machine, by using 'mount -t corbafs -o IOR:... none /mnt/corba' ++ ++This are just some of the features available _RIGHT_NOW_ that are ++supported by kORBit. I'm sure that YOU can think of many more. ++ ++Implementation: ++We implemented this port by providing a user->kernel mapping layer that ++consists of providing standard system header files for the "user" code to ++#include. In these header files, we do the mapping required. For ++example, we implement a <stdio.h> that #defines printf to printk (as a ++trivial example). Only user level code sees or uses these wrappers... all ++of our modifications to the Linux kernel are contained within the ++linux/net/korbit subdirectory. ++ ++This is currently implemented with a 2.4.0test10 kernel, although forward ++porting should be very easy. This project was implemented as a cs423 ++semester project by Chris Lattner, Fredrik Vraalsen, Andy Reitz, and Keith ++Wessel at the University of Illinois @ Urbana Champaign. ++ ++Unresolved issues: ++* Our poll model is not optimial. Currently we actually do a real poll on ++ a (struct socket *) set. This causes relatively high latencies (on the ++ order 1 second, worst case) for CORBA requests. Our waitqueues are not ++ working quite as well as they should. :) ++* Security is completely unimplemented. Someone could use corba ++ interfaces to read any file on your system, for example (if the ++ CORBA-FileServer module is installed). Thus, this is really more for ++ prototyping and development than actual real world use. :) ++ ++If you have any questions or comments, please feel free to contact us at: ++ ++Chris Lattner, Fredrik Vraalsen, Andy Reitz, Keith Wessel ++<korbit-cvs@lists.sourceforge.net> ++ ++btw, yes we are quite crazy, but what good is it to be normal and ++conformist afterall? :) ++ ++ ++ +diff -urN linux-2.4.1/Makefile linux-2.4.1-korbit/Makefile +--- linux-2.4.1/Makefile Tue Jan 30 09:19:26 2001 ++++ linux-2.4.1-korbit/Makefile Thu Feb 1 15:48:45 2001 +@@ -70,7 +70,7 @@ + # images. Uncomment if you want to place them anywhere other than root. + # + +-#export INSTALL_PATH=/boot ++export INSTALL_PATH=/boot + + # + # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +diff -urN linux-2.4.1/README.korbit linux-2.4.1-korbit/README.korbit +--- linux-2.4.1/README.korbit Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/README.korbit Thu Feb 1 11:46:48 2001 +@@ -0,0 +1,83 @@ ++ ==================== ++ KORBit: A CORBA ORB ++ For The Linux Kernel ++ ==================== ++ ++ Submitted as a final project in CS423 by ++ Chris Lattner <lattner@uiuc.edu>, ++ Andy Reitz <areitz@uiuc.edu>, ++ Fredrik Vraalsen <vraalsen@uiuc.edu>, and ++ Keith Wessel <kwessel@uiuc.edu> ++ ++ December 8, 2000 ++ ++ ++About: ++====== ++KORBit is a port of the CORBA Object Request Broker ORBit to the Linux ++kernel. For more information, see http://korbit.sourceforge.net/ ++ ++In order to use this code, you need to have ORBit-0.5.3 or later ++installed (including the development environment). The KORBit server ++modules make use of the ORBit IDL Compiler during the build process. ++ ++Building The Code: ++================== ++In order to compile and run KORBit you need a recent 2.4.0-test ++version of the Linux kernel (KORBit is developed on 2.4.0-test10). ++ ++To obtain a copy of the KORBit source code, see the webpage above. ++Once you have untar'ed the source code, copy the contents of the linux ++subdirectory of KORBit into the Linux root source directory ++(e.g. /usr/src/linux). ++ ++Run your favourite configuration option for Linux (e.g. 'make ++menuconfig'). To enable KORBit support in the kernel, go into the ++'Networking options' section of the configuration and enable 'Kernel ++ORB'. Then add the various CORBA services that you wish to run in the ++kernel. ++ ++NOTE: The Kernel ORB *must* be compiled statically into the kernel ++(answer 'Y') and CORBA services *must* be compiled as modules (answer ++'M') at the moment. ++ ++Then compile and install the Linux kernel in the standard way, e.g.: ++ ++make dep ; make clean ; make bzImage ; make modules ; make modules_install ++ ++Copy System.map and arch/<i386|whatever>/boot/bzImage to the proper ++places (/boot), edit your lilo.conf, run lilo and reboot. ++ ++You should now be able to use CORBA in your Linux kernel! Remember, ++this is *pre-alpha* software! Use on your own risk! Don't come to us ++crying if your machine blows up... ++ ++Using Our Example KORBit Objects: ++================================= ++The "CORBA Echo Server" is effectively our "hello world" object. Once ++loaded into the kernel, module will instantiate an object that ++implements the "echoString()" interface. This method allows the client ++to send a string, which will be printed on the system console. Then, ++it will return a random number, which the client will print. Thus, ++after running this test, you will verify that two-way communication is ++working between KORBit and your ORB of choice. ++ ++To insert this module into your newly-compiled kernel, type ++ ++insmod /lib/modules/2.4.0-test10/kernel/net/korbit/modules/Echo/server/corba-echo-server.o ++ ++Next verify that this module is actually loaded, by invoking ++"lsmod". You should see something like this: ++ ++ Module Size Used by ++ corba-echo-server 3344 0 (unused) ++ ++Now, you can grab the IOR to this object by typing "cat ++/proc/corba/echo-server". Now, you need to build the echo client, ++which will use this IOR in order to connect to the echo server. This ++can be accomplished by simply changing to the ++"/usr/src/linux/net/korbit/modules/Echo/client" directory, and then ++typing "make". Once finished, simply type "./echo-client `cat ++/proc/corba/echo-server`", and then cross your fingers! ++ ++ +diff -urN linux-2.4.1/Rules.make linux-2.4.1-korbit/Rules.make +--- linux-2.4.1/Rules.make Sat Dec 30 00:07:19 2000 ++++ linux-2.4.1-korbit/Rules.make Thu Feb 1 15:46:07 2001 +@@ -222,9 +222,9 @@ + + $(MODINCL)/%.ver: %.c + @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \ +- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \ ++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \ + echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \ +- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \ ++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \ + | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \ + if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \ + else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \ +diff -urN linux-2.4.1/korbit.patch linux-2.4.1-korbit/korbit.patch +--- linux-2.4.1/korbit.patch Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/korbit.patch Thu Feb 1 11:46:48 2001 +@@ -0,0 +1,43 @@ ++--- linux/Rules.make.orig Wed Jan 31 22:50:40 2001 +++++ linux/Rules.make Thu Feb 1 01:39:46 2001 ++@@ -222,9 +222,9 @@ ++ ++ $(MODINCL)/%.ver: %.c ++ @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \ ++- echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \ +++ echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \ ++ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \ ++- $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \ +++ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \ ++ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \ ++ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \ ++ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \ ++--- linux/net/Config.in.orig Wed Jan 31 22:39:32 2001 +++++ linux/net/Config.in Thu Feb 1 01:40:02 2001 ++@@ -30,6 +30,7 @@ ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ source net/khttpd/Config.in +++ source net/korbit/Config.in ++ fi ++ fi ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++--- linux/net/Makefile.orig Thu Feb 1 01:41:42 2001 +++++ linux/net/Makefile Thu Feb 1 01:41:35 2001 ++@@ -7,7 +7,7 @@ ++ ++ O_TARGET := network.o ++ ++-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched +++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit ++ export-objs := netsyms.o ++ ++ subdir-y := core ethernet ++@@ -27,6 +27,7 @@ ++ endif ++ ++ subdir-$(CONFIG_KHTTPD) += khttpd +++subdir-$(CONFIG_KORBIT) += korbit ++ subdir-$(CONFIG_NETLINK) += netlink ++ subdir-$(CONFIG_PACKET) += packet ++ subdir-$(CONFIG_NET_SCHED) += sched +diff -urN linux-2.4.1/makekorbit.sh linux-2.4.1-korbit/makekorbit.sh +--- linux-2.4.1/makekorbit.sh Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/makekorbit.sh Thu Feb 1 11:46:48 2001 +@@ -0,0 +1,4 @@ ++#!/bin/sh ++ ++make CFLAGS="-D__KERNEL__ -I`pwd`/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -march=k6 -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc" -C net/korbit TOPDIR=`pwd` ++ +diff -urN linux-2.4.1/net/CVS/Entries linux-2.4.1-korbit/net/CVS/Entries +--- linux-2.4.1/net/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/CVS/Entries Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++D +diff -urN linux-2.4.1/net/CVS/Entries.Log linux-2.4.1-korbit/net/CVS/Entries.Log +--- linux-2.4.1/net/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/CVS/Entries.Log Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++A D/korbit//// +diff -urN linux-2.4.1/net/CVS/Repository linux-2.4.1-korbit/net/CVS/Repository +--- linux-2.4.1/net/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/CVS/Repository Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net +diff -urN linux-2.4.1/net/CVS/Root linux-2.4.1-korbit/net/CVS/Root +--- linux-2.4.1/net/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/CVS/Root Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/Config.in linux-2.4.1-korbit/net/Config.in +--- linux-2.4.1/net/Config.in Tue Oct 10 19:33:52 2000 ++++ linux-2.4.1-korbit/net/Config.in Thu Feb 1 15:46:07 2001 +@@ -30,6 +30,7 @@ + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + source net/khttpd/Config.in ++ source net/korbit/Config.in + fi + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +diff -urN linux-2.4.1/net/Makefile linux-2.4.1-korbit/net/Makefile +--- linux-2.4.1/net/Makefile Sat Dec 30 00:07:24 2000 ++++ linux-2.4.1-korbit/net/Makefile Thu Feb 1 15:46:07 2001 +@@ -7,7 +7,7 @@ + + O_TARGET := network.o + +-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched ++mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched korbit + export-objs := netsyms.o + + subdir-y := core ethernet +@@ -27,6 +27,7 @@ + endif + + subdir-$(CONFIG_KHTTPD) += khttpd ++subdir-$(CONFIG_KORBIT) += korbit + subdir-$(CONFIG_NETLINK) += netlink + subdir-$(CONFIG_PACKET) += packet + subdir-$(CONFIG_NET_SCHED) += sched +diff -urN linux-2.4.1/net/korbit/CVS/Entries linux-2.4.1-korbit/net/korbit/CVS/Entries +--- linux-2.4.1/net/korbit/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/CVS/Entries Thu Feb 1 11:46:49 2001 +@@ -0,0 +1,6 @@ ++/Config.in/1.3/Thu Feb 1 09:46:49 2001// ++/Makefile/1.7/Thu Feb 1 09:46:49 2001// ++/config.h/1.2/Thu Feb 1 09:46:49 2001// ++/exported_symbols.c/1.8/Thu Feb 1 09:46:49 2001// ++/korbit.h/1.2/Thu Feb 1 09:46:49 2001// ++D +diff -urN linux-2.4.1/net/korbit/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/CVS/Entries.Log +--- linux-2.4.1/net/korbit/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/CVS/Entries.Log Thu Feb 1 11:47:15 2001 +@@ -0,0 +1,7 @@ ++A D/IIOP//// ++A D/ORBitutil//// ++A D/include//// ++A D/kglib//// ++A D/modules//// ++A D/orb//// ++A D/sup//// +diff -urN linux-2.4.1/net/korbit/CVS/Repository linux-2.4.1-korbit/net/korbit/CVS/Repository +--- linux-2.4.1/net/korbit/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/CVS/Repository Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit +diff -urN linux-2.4.1/net/korbit/CVS/Root linux-2.4.1-korbit/net/korbit/CVS/Root +--- linux-2.4.1/net/korbit/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/CVS/Root Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/Config.in linux-2.4.1-korbit/net/korbit/Config.in +--- linux-2.4.1/net/korbit/Config.in Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/Config.in Thu Feb 1 11:46:49 2001 +@@ -0,0 +1,8 @@ ++# ++# KORBit ++# ++ ++#tristate ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT ++bool ' Kernel ORB (EXPERIMENTAL)' CONFIG_KORBIT ++ ++source net/korbit/modules/Config.in +diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Entries linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries +--- linux-2.4.1/net/korbit/IIOP/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Entries Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,15 @@ ++/IIOP-config.h/1.1.1.1/Thu Feb 1 09:46:50 2001// ++/IIOP-design.txt/1.1.1.1/Thu Feb 1 09:46:50 2001// ++/IIOP-private.h/1.2/Thu Feb 1 09:46:50 2001// ++/IIOP-types.h/1.1.1.1/Thu Feb 1 09:46:50 2001// ++/IIOP.h/1.1.1.1/Thu Feb 1 09:46:50 2001// ++/Makefile/1.4/Thu Feb 1 09:46:51 2001// ++/connection.c/1.19/Thu Feb 1 09:46:51 2001// ++/encoders.c/1.1.1.1/Thu Feb 1 09:46:51 2001// ++/giop-msg-buffer.c/1.12/Thu Feb 1 09:46:51 2001// ++/giop-msg-buffer.h/1.1.1.1/Thu Feb 1 09:46:51 2001// ++/iiop-encoders.h/1.1.1.1/Thu Feb 1 09:46:51 2001// ++/iiop-endian.c/1.1.1.1/Thu Feb 1 09:46:51 2001// ++/iiop-endian.h/1.1.1.1/Thu Feb 1 09:46:51 2001// ++/iiop-endianP.h/1.1.1.1/Thu Feb 1 09:46:51 2001// ++D +diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Repository linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository +--- linux-2.4.1/net/korbit/IIOP/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Repository Thu Feb 1 11:46:50 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/IIOP +diff -urN linux-2.4.1/net/korbit/IIOP/CVS/Root linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root +--- linux-2.4.1/net/korbit/IIOP/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/CVS/Root Thu Feb 1 11:46:49 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-config.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h +--- linux-2.4.1/net/korbit/IIOP/IIOP-config.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-config.h Thu Feb 1 11:46:50 2001 +@@ -0,0 +1,5 @@ ++/* The size of the chunks that are used for indirect pieces of messages. ++ Too low, and you'll have a lot of malloc overhead. Too high, and you'll ++ get wasted mem. ++*/ ++#define GIOP_INDIRECT_CHUNK_SIZE 1024 +diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-design.txt linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt +--- linux-2.4.1/net/korbit/IIOP/IIOP-design.txt Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-design.txt Thu Feb 1 11:46:50 2001 +@@ -0,0 +1,14 @@ ++ ++void Hello_hello(CORBA_Object anobj, const char *arg1, CORBA_Environment *ev) ++ ++If we're doing a local call (i.e. shared library object activation), ++just do it. ++ ++If we're doing a remote call, we need to setup generic header ++(utilfunc), setup request header (utilfunc), encode arguments (stubs), ++send the message headers & body (utilfunc) and wait for a reply (XXX ++define more clearly). When we get the reply, we need to read the ++reply(utilfunc), decode the return value & out/inout arguments(stubs) ++& fill them in (or decode the exception that resulted (utilfunc)), and ++return. ++ +diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-private.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h +--- linux-2.4.1/net/korbit/IIOP/IIOP-private.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-private.h Thu Feb 1 11:46:50 2001 +@@ -0,0 +1,46 @@ ++#ifndef IIOP_PRIVATE_H ++#define IIOP_PRIVATE_H 1 ++ ++ ++#include "config.h" ++ ++#if defined(HAVE_POLL) && defined(I_WANT_POLL) ++#define USE_POLL ++#else ++#undef USE_POLL ++#endif ++ ++#ifdef HAVE_SYS_POLL_H ++#include <sys/poll.h> ++#endif ++ ++#include <sys/time.h> ++#include <sys/types.h> ++#include <unistd.h> ++ ++#include <glib.h> ++ ++typedef struct { ++ GList *list; ++ gboolean connection_list_changed; ++#ifndef __KORBIT__ ++ GPtrArray *fd_to_connection_mapping; ++#else /* __KORBIT__ */ ++ GHashTable *fd_to_connection_mapping; ++#endif /* __KORBIT__ */ ++# ifdef USE_POLL ++ GArray *pollset; ++# else ++ fd_set selectset_rd, selectset_ex; ++# endif ++ int max_fd; ++} GIOPConnectionList; ++ ++extern GIOPConnectionList giop_connection_list; ++ ++/* If you get a buffer that you didn't want, add it to the list! */ ++void giop_received_list_push(GIOPRecvBuffer *recv_buffer); ++GIOPRecvBuffer *giop_received_list_pop(void); ++ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/IIOP/IIOP-types.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h +--- linux-2.4.1/net/korbit/IIOP/IIOP-types.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP-types.h Thu Feb 1 11:46:50 2001 +@@ -0,0 +1,76 @@ ++#ifndef IIOP_TYPES_H ++#define IIOP_TYPES_H 1 ++ ++/* XXX todo sync this up with basic_types.h if needed */ ++#include <unistd.h> ++#include <netinet/in.h> ++#include <sys/un.h> ++ ++#include <ORBitutil/basic_types.h> ++ ++typedef enum { ++ GIOP_CONNECTION_SERVER, /* Not a real connection to any place - just ++ listening */ ++ GIOP_CONNECTION_CLIENT ++} GIOPConnectionClass; ++ ++typedef struct _GIOPConnection GIOPConnection; ++struct _GIOPConnection { ++ enum { GIOP_CONNECTION_NONE, GIOP_CONNECTION_IIOP } connection_type; ++ void (*destroy_func)(GIOPConnection *connection); ++ ++ gint refcount; ++ GIOPConnectionClass connection_class; ++ ++ int fd; ++ ++ /* You can access these if you wish. */ ++ gpointer orb_data; ++ gpointer user_data; ++ /* end accessable stuff */ ++ ++ guchar is_valid, was_initiated, is_auth; ++ ++ gpointer incoming_msg; /* GIOPRecvBuffer */ ++}; ++ ++#define GIOP_CONNECTION(x) ((GIOPConnection *)(x)) ++#define GIOP_CONNECTION_GET_FD(x) (GIOP_CONNECTION((x))->fd) ++ ++typedef enum { IIOP_IPV4, IIOP_IPV6, IIOP_USOCK } IIOPConnectionType; ++ ++typedef struct { ++ GIOPConnection giop_connection; ++ ++ gboolean is_serversock; ++ IIOPConnectionType icnxtype; ++ union { ++ struct { ++ char *hostname; ++ struct sockaddr_in location; ++ } ipv4; ++ struct sockaddr_un usock; ++ /* Yes this is a config.h define, and no it doesn't matter, ++ because this structure should only be used internally anyways */ ++#ifdef HAVE_IPV6 ++ struct { ++ char *hostname; ++ struct sockaddr_in6 location; ++ } ipv6; ++#endif ++ } u; ++} IIOPConnection; ++ ++#define IIOP_CONNECTION(x) ((IIOPConnection *)(x)) ++ ++#if defined(DEBUG_sopwith_connection_refcounting) ++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); g_print("! reffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); }G_STMT_END ++ ++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; g_print("! dereffing fd %d in " __PRETTY_FUNCTION__ ":%d to %d\n", GIOP_CONNECTION_GET_FD(x), __LINE__, GIOP_CONNECTION(x)->refcount); if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END ++#else ++#define giop_connection_ref(x) G_STMT_START{ (GIOP_CONNECTION(x)->refcount++); }G_STMT_END ++ ++#define giop_connection_unref(x) G_STMT_START{ GIOP_CONNECTION(x)->refcount--; if(GIOP_CONNECTION(x)->refcount <= 0) giop_connection_free(x); }G_STMT_END ++#endif ++ ++#endif /* IIOP_TYPES_H */ +diff -urN linux-2.4.1/net/korbit/IIOP/IIOP.h linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h +--- linux-2.4.1/net/korbit/IIOP/IIOP.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/IIOP.h Thu Feb 1 16:19:47 2001 +@@ -0,0 +1,52 @@ ++#ifndef IIOP_H ++#define IIOP_H 1 ++ ++#include <unistd.h> ++#include <ORBitutil/util.h> ++#include "IIOP-config.h" ++#include "IIOP-types.h" ++#include "giop-msg-buffer.h" ++#include "iiop-encoders.h" ++#include "iiop-endian.h" ++ ++/* We don't speak GIOP 1.0, sosumi */ ++#define GIOP_1_1 ++ ++ ++void giop_init(const char *argv0); ++ ++/* You use this to get a pointer to a new (or existing) connection ++ that has the specified host/port characteristics */ ++IIOPConnection *iiop_connection_get(const char *host, gushort port, ++ gboolean existing_only); ++/* Similar, but for UNIX sockets */ ++IIOPConnection *iiop_connection_unix_get(const char *sockpath, ++ gboolean existing_only); ++ ++/* gives us a local socket that other people can connect to... */ ++IIOPConnection *iiop_connection_server(void); ++IIOPConnection *iiop_connection_server_ipv6(void); ++IIOPConnection *iiop_connection_server_unix(const char *sockpath); ++ ++void giop_main_quit(void); ++void giop_main(void); /* main loop for the program if none other is given, ++ and also used while waiting for a reply */ ++void giop_main_iterate(gboolean blocking); ++void giop_main_handle_connection(GIOPConnection *connection); ++void giop_main_handle_connection_exception(GIOPConnection *connection); ++GIOPRecvBuffer *giop_main_next_message(gboolean blocking); ++GIOPRecvBuffer *giop_main_next_message_2(gboolean blocking, ++ GIOPConnection *monitor); ++GIOPConnection *giop_check_connections(gboolean block_for_reply); ++ ++/* This assumes that the appropriate GIOP_CLOSECONNECTION message ++ has been sent to the peer */ ++void giop_connection_free(GIOPConnection *connection); ++ ++/* Called when a connection is created */ ++extern void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx); ++/* Called when a connection is about to be destroyed */ ++extern void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx); ++extern void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer); ++ ++#endif /* IIOP_H */ +diff -urN linux-2.4.1/net/korbit/IIOP/Makefile linux-2.4.1-korbit/net/korbit/IIOP/Makefile +--- linux-2.4.1/net/korbit/IIOP/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/Makefile Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,18 @@ ++# ++# Makefile for KORBit/IIOP ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .o file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := IIOPlib.o ++ ++#obj-m := $(O_TARGET) ++obj-y := connection.o encoders.o giop-msg-buffer.o iiop-endian.o ++ ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.1/net/korbit/IIOP/connection.c linux-2.4.1-korbit/net/korbit/IIOP/connection.c +--- linux-2.4.1/net/korbit/IIOP/connection.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/connection.c Thu Feb 1 19:26:07 2001 +@@ -0,0 +1,1565 @@ ++#include "config.h" ++ ++#if defined(HAVE_POLL) && defined(I_WANT_POLL) ++#define USE_POLL ++#else ++#undef USE_POLL ++#endif ++ ++#ifndef _XOPEN_SOURCE_EXTENDED ++# define _XOPEN_SOURCE_EXTENDED 1 ++# define WE_DEFINED_XOPEN_SOURCE_EXTENDED 1 ++#endif ++#include "iiop-endianP.h" ++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED ++# undef _XOPEN_SOURCE_EXTENDED ++#endif ++#include "IIOP.h" ++#include "IIOP-private.h" ++#include "giop-msg-buffer.h" ++#include <stdlib.h> ++#include <unistd.h> ++#ifdef ORBIT_DEBUG ++#include <errno.h> ++#endif ++#include <sys/types.h> ++#include <fcntl.h> ++#include <sys/socket.h> ++#include <sys/un.h> ++#ifndef _XOPEN_SOURCE_EXTENDED ++# define _XOPEN_SOURCE_EXTENDED 1 ++#endif ++#include <arpa/inet.h> ++#include <netdb.h> ++#ifdef WE_DEFINED_XOPEN_SOURCE_EXTENDED ++# undef _XOPEN_SOURCE_EXTENDED ++#endif ++#include <ctype.h> ++#include <string.h> ++#include <sys/time.h> ++#include <sys/ioctl.h> ++#include <signal.h> ++#include <syslog.h> ++#include <stdio.h> ++ ++/* ++#ifdef O_NONBLOCK ++#undef O_NONBLOCK ++#endif ++#define O_NONBLOCK 0 ++*/ ++ ++#if defined(HAVE_TCPD_H) && defined(HAVE_HOSTS_ACCESS) ++#include <tcpd.h> ++#endif ++ ++#if 0 ++#include <malloc.h> ++ ++static struct mallinfo mi1, mi2; ++ ++#define AM() mi1 = mallinfo(); ++#define PM(x) mi2 = mallinfo(); printf(x ": used %d, now %d\n", \ ++mi2.uordblks - mi1.uordblks, mi2.uordblks); ++#endif ++ ++#ifdef HAVE_POLL ++#include <sys/poll.h> ++#endif ++ ++#ifndef SUN_LEN ++/* This system is not POSIX.1g. */ ++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ ++ + strlen ((ptr)->sun_path)) ++#endif ++ ++void (*IIOPAddConnectionHandler)(GIOPConnection *newcnx) = NULL; ++void (*IIOPRemoveConnectionHandler)(GIOPConnection *oldcnx) = NULL; ++void (*IIOPIncomingMessageHandler)(GIOPRecvBuffer *recv_buffer) = NULL; ++ ++static void giop_connection_add_to_list (GIOPConnection *cnx); ++static void giop_connection_remove_from_list (GIOPConnection *cnx); ++ ++static void iiop_init (void); ++static void iiop_connection_server_accept (GIOPConnection *connection); ++static void iiop_connection_destroy (IIOPConnection *connection); ++static IIOPConnection *iiop_connection_new (const char *host, gushort port); ++static IIOPConnection *iiop_connection_unix_new (const char *sockpath); ++static void iiop_unlink_unix_sockets (void); ++ ++DEFINE_LOCK(giop_connection_list); ++GIOPConnectionList giop_connection_list; ++static GSList *iiop_unix_socket_list = NULL; ++ ++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H) ++static const char *argv0_val = NULL; ++#endif ++ ++struct fd_hash_elem ++{ ++ guint fd; ++ GIOPConnection *cnx; ++}; ++ ++static guint fd_hash_func(gconstpointer key) ++{ ++ const guint *key_ptr = (guint *)key; ++ guint result = *key_ptr >> 2; ++ return result; ++} ++ ++static gint fd_compare_func(gconstpointer a, gconstpointer b) ++{ ++ const guint *a_ptr = (guint *)a; ++ const guint *b_ptr = (guint *)b; ++ return *a_ptr == *b_ptr; ++} ++ ++static gboolean fd_hash_clear(gpointer key, gpointer value, gpointer user_data) ++{ ++ struct fd_hash_elem *el = (struct fd_hash_elem *)value; ++ g_free(el); ++ return TRUE; ++} ++ ++/* ++ * giop_init ++ * ++ * Inputs: None ++ * Outputs: None ++ * ++ * Side effects: Initializes giop_connection_list ++ * Global data structures used: giop_connection_list ++ * ++ * Description: Initializes giop_connection_list. Calls ++ * giop_message_buffer_init() to initialize the ++ * message_buffer subsystem. Calls iiop_init() ++ * to perform IIOP-specific initialization. ++ */ ++ ++void giop_init(const char *argv0) ++{ ++#ifndef __KERNEL__ ++ struct sigaction mypipe; ++#endif ++ g_assert(sizeof(GIOPMessageHeader) == 12); ++ ++#if defined(HAVE_HOSTS_ACCESS) && defined (HAVE_TCPD_H) ++ argv0_val = g_strdup(g_basename(argv0)); /* For TCP wrappers */ ++#endif ++ ++#ifndef __KERNEL__ ++ memset(&mypipe, '\0', sizeof(mypipe)); ++ mypipe.sa_handler = SIG_IGN; ++ ++ sigaction(SIGPIPE, &mypipe, NULL); ++#endif ++ ++ giop_message_buffer_init(); ++ ++ INIT_LOCK(giop_connection_list); ++ ++ giop_connection_list.list = NULL; ++ giop_connection_list.connection_list_changed = FALSE; ++ ++#ifdef USE_POLL ++ giop_connection_list.pollset = g_array_new(FALSE, FALSE, ++ sizeof(struct pollfd)); ++#else ++ FD_ZERO(&giop_connection_list.selectset_rd); ++ FD_ZERO(&giop_connection_list.selectset_ex); ++#endif ++ ++#ifndef __KORBIT__ ++ giop_connection_list.fd_to_connection_mapping = g_ptr_array_new(); ++#else ++ giop_connection_list.fd_to_connection_mapping = ++ g_hash_table_new(&fd_hash_func, ++ &fd_compare_func); ++#endif ++ ++ /* ++ * This also needs to do any transport-specific initialization ++ * as appropriate ++ */ ++ iiop_init(); ++} ++ ++/*** giop_connection_init ++ * ++ * Inputs: 'giop_connection' - memory region allocated for use as a ++ * GIOPConnection. ++ * 'cnxclass' - the class of connection that will be stored ++ * here (SERVER, CLIENT) ++ * ++ * Outputs: None ++ * ++ * Side effects: Initializes 'giop_connection'. ++ * ++ * Description: Basic setup of a GIOPConnection. ++ * Sets is_valid to FALSE because it is the responsibility of ++ * the transport-specific initialization routine to make ++ * a connection valid. ++ */ ++ ++static void giop_connection_init(GIOPConnection *giop_connection, ++ GIOPConnectionClass cnxclass) ++{ ++ giop_connection->connection_type = GIOP_CONNECTION_NONE; ++ giop_connection->refcount = 0; ++ giop_connection->connection_class = cnxclass; ++ giop_connection->is_valid = FALSE; ++ giop_connection->is_auth = FALSE; ++ giop_connection->was_initiated = FALSE; ++} ++ ++/* ++ * giop_connection_free ++ * Inputs: 'connection' ++ * Outputs: None ++ * Side effects: Makes the 'connection' invalid as a GIOPConnection ++ * and as a gpointer. ++ * ++ * Description: Calls giop_connection_remove_from_list() to ++ * stop the connection from being used for incoming. ++ * ++ * If a transport-specific finalization function has ++ * been provided, call it. ++ * ++ * Free the memory block at '*connection'. ++ * ++ */ ++void giop_connection_free(GIOPConnection *connection) ++{ ++ g_return_if_fail(connection != NULL); ++ giop_connection_remove_from_list(connection); ++ ++ if(connection->is_valid && connection->destroy_func) ++ connection->destroy_func(connection); ++ ++ connection->is_valid = FALSE; ++ ++ if(connection->incoming_msg) { ++ GIOPRecvBuffer *buf; ++ ++ buf = connection->incoming_msg; ++ connection->incoming_msg = NULL; ++ giop_recv_buffer_unuse(buf); ++ } ++ ++ g_free(connection); ++} ++ ++/* ++ * giop_connection_list_recreate ++ * ++ * Inputs: None ++ * Outputs: None ++ * ++ * Side effects: giop_connection_list changes. ++ * ++ * Global data structures used: giop_connection_list ++ * ++ * Description: ++ * When new connections are added to giop_connection_list.list, ++ * the data structures passed to poll() or select() (OS-dependant) ++ * must be recreated to match this list. ++ * ++ * [We do this at add-connection/remove-connection time ++ * instead of every time a poll/select is done in order to ++ * speed things up a little] ++ * ++ * This function reinitializes the OS-specific file ++ * descriptor data structure and then adds all the file ++ * descriptors in the list to it. ++ * ++ * It also regenerates the array that maps file descriptors ++ * into GIOPConnection*'s ++ * ++ */ ++static void ++giop_connection_list_recreate(void) ++{ ++ int curfd; ++ GList *item; ++ GIOPConnection *cnx; ++#ifdef USE_POLL ++ struct pollfd new_poll; ++ ++ new_poll.revents = 0; ++#endif ++ ++ giop_connection_list.max_fd = 0; ++ for(item = giop_connection_list.list; item; item = g_list_next(item)) ++ { ++ cnx = item->data; ++ curfd = GIOP_CONNECTION_GET_FD(cnx); ++ ++ if(curfd > giop_connection_list.max_fd) ++ giop_connection_list.max_fd = curfd; ++ } ++ ++#ifndef __KORBIT__ ++ g_ptr_array_set_size(giop_connection_list.fd_to_connection_mapping, ++ giop_connection_list.max_fd + 1); ++#else ++ g_hash_table_foreach_remove(giop_connection_list.fd_to_connection_mapping, ++ fd_hash_clear, ++ NULL); ++#endif ++ ++#ifdef USE_POLL ++ g_array_set_size(giop_connection_list.pollset, 0); ++#else ++ FD_ZERO(&giop_connection_list.selectset_rd); ++ FD_ZERO(&giop_connection_list.selectset_ex); ++#endif ++ ++ for(item = giop_connection_list.list; item; item = g_list_next(item)) ++ { ++ struct fd_hash_elem *el; ++ ++ cnx = item->data; ++ curfd = GIOP_CONNECTION_GET_FD(cnx); ++ ++#ifndef __KORBIT__ ++ giop_connection_list.fd_to_connection_mapping->pdata[curfd] = cnx; ++#else ++ el = g_new(struct fd_hash_elem, 1); ++ el->fd = curfd; ++ el->cnx = cnx; ++ g_hash_table_insert(giop_connection_list.fd_to_connection_mapping, ++ &(el->fd), ++ el); ++#endif ++ ++# ifdef USE_POLL ++ new_poll.fd = curfd; ++ new_poll.events = POLLIN|POLLPRI; ++ g_array_append_val(giop_connection_list.pollset, ++ new_poll); ++# else ++ FD_SET(curfd, &giop_connection_list.selectset_rd); ++ FD_SET(curfd, &giop_connection_list.selectset_ex); ++# endif ++ } ++} ++ ++/* ++ * giop_connection_add_to_list ++ * ++ * Inputs: 'cnx' - a GIOPConnection that the user wishes added to the list ++ * Outputs: None ++ * ++ * Side effects: Modifies giop_connection_list ++ * Global data structures used: giop_connection_list ++ * Bugs: Does not check for duplicate additions. ++ * ++ * Description: ++ * Adds a connection to the list of active connections. ++ */ ++static void ++giop_connection_add_to_list(GIOPConnection *cnx) ++{ ++ g_return_if_fail(cnx->is_valid == FALSE); ++ ++ cnx->is_valid = TRUE; ++ ++ GET_LOCK(giop_connection_list); ++ giop_connection_list.list = g_list_prepend(giop_connection_list.list, cnx); ++ ++ giop_connection_list_recreate(); ++ ++ RELEASE_LOCK(giop_connection_list); ++ ++ if(IIOPAddConnectionHandler) ++ IIOPAddConnectionHandler(cnx); ++ ++ giop_connection_ref(cnx); ++} ++ ++/* ++ * giop_connection_remove_from_list ++ * ++ * Inputs: 'cnx' - a GIOPConnection that the user wishes ++ * Outputs: None ++ * ++ * Side effects: Modifies giop_connection_list ++ * Global data structures used: giop_connection_list ++ * ++ * Description: ++ * Removes a connection from the list of active connections. ++ * Calls the library user's "I removed connection" handler if it ++ * exists. ++ * ++ * Bugs: Does not check for duplicate removals. This may not be "bad" though. ++ */ ++void ++giop_connection_remove_from_list(GIOPConnection *cnx) ++{ ++ GList *link; ++ ++ GET_LOCK(giop_connection_list); ++ ++ link = g_list_find(giop_connection_list.list, cnx); ++ ++ if(!link) ++ goto out; ++ ++ if(IIOPRemoveConnectionHandler && cnx->is_valid) ++ IIOPRemoveConnectionHandler(cnx); ++ ++ giop_connection_list.list = g_list_remove_link(giop_connection_list.list, ++ link); ++ g_list_free_1(link); ++ ++ giop_connection_unref(cnx); ++ ++ giop_connection_list_recreate(); ++ out: ++ RELEASE_LOCK(giop_connection_list); ++} ++ ++/************************************************ ++ * Routines specific to the IIOP/IPv4 transport * ++ ************************************************/ ++ ++/* ++ * iiop_init ++ * ++ * Inputs: None ++ * Outputs: None ++ * ++ * Side effects: Initializes iiop_unix_socket_list ++ * Global data structures used: iiop_unix_socket_list ++ * ++ * Description: Initializes iiop_unix_socket_list. ++ * Registers Unix domain sockets for ++ * removal at server termination. ++ */ ++static void ++iiop_init(void) ++{ ++#ifndef __KERNEL__ ++ g_atexit(iiop_unlink_unix_sockets); ++#endif ++} ++ ++/* ++ * iiop_connection_init ++ * ++ * Inputs: 'connection' - a memory region that needs to be initialized as ++ * an 'IIOPConnection'. ++ * ++ * Side effects: initializes 'connection' ++ * ++ * Description: Performs the IIOP-specific initialization of an ++ * IIOPConnection. giop_connection_init is called. ++ * ++ */ ++void ++iiop_connection_init(IIOPConnection *connection, ++ GIOPConnectionClass cnxclass, ++ IIOPConnectionType iioptype) ++{ ++ giop_connection_init(GIOP_CONNECTION(connection), cnxclass); ++ ++ GIOP_CONNECTION(connection)->connection_type = ++ GIOP_CONNECTION_IIOP; ++ ++ GIOP_CONNECTION(connection)->destroy_func = ++ (void (*)(GIOPConnection *))iiop_connection_destroy; ++ ++ connection->icnxtype = iioptype; ++} ++ ++/* ++ * iiop_connection_from_fd ++ * ++ * Inputs: 'fd' - a file descriptor that attention should be paid to ++ * Outputs: 'fd_cnx' - the created connection ++ * ++ * Description: This is intended to be used on a file descriptor ++ * that has been accept()'d. It creates the connection ++ * and fills in the connection information, then adds ++ * it to the active list. ++ */ ++IIOPConnection * ++iiop_connection_from_fd(int fd, IIOPConnection *parent) ++{ ++ IIOPConnection *fd_cnx; ++ struct hostent *hent; ++ socklen_t n; ++ ++ g_assert(fd >= 0); ++ ++ fd_cnx = g_new0(IIOPConnection, 1); ++ ++ iiop_connection_init(fd_cnx, GIOP_CONNECTION_CLIENT, parent->icnxtype); ++ ++ GIOP_CONNECTION(fd_cnx)->fd = fd; ++ ++ switch(parent->icnxtype) { ++ case IIOP_IPV4: ++ n = sizeof(struct sockaddr_in); ++ if(getpeername(GIOP_CONNECTION_GET_FD(fd_cnx), (struct sockaddr *)&fd_cnx->u.ipv4.location, &n)) ++ { ++ fd_cnx->u.ipv4.hostname = g_strdup(""); ++ } ++ else ++ { ++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv4.location.sin_addr.s_addr, 4, AF_INET); ++ if(hent) ++ { ++ fd_cnx->u.ipv4.hostname = g_strdup(hent->h_name); ++ } ++ else ++ { ++ fd_cnx->u.ipv4.hostname = inet_ntoa(*((struct in_addr *)&fd_cnx->u.ipv4.location.sin_addr)); ++ } ++ } ++ break; ++ ++ case IIOP_USOCK: ++ n = sizeof(struct sockaddr_un); ++ fd_cnx->u.usock.sun_family = AF_UNIX; ++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx), ++ (struct sockaddr *)&fd_cnx->u.usock, &n); ++ break; ++ ++#ifdef HAVE_IPV6 ++ case IIOP_IPV6: ++ n = sizeof(struct sockaddr_in6); ++ getpeername(GIOP_CONNECTION_GET_FD(fd_cnx), ++ (struct sockaddr *)&fd_cnx->u.ipv6.location, &n); ++ hent = gethostbyaddr((const char *)&fd_cnx->u.ipv6.location.sin6_addr, ++ sizeof(fd_cnx->u.ipv6.location.sin6_addr), AF_INET6); ++ fd_cnx->u.ipv6.hostname = g_strdup(hent->h_name); ++ break; ++#endif ++ ++ default: ++ g_error("Unsupported connection type %d", parent->icnxtype); ++ } ++ ++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFD, ++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFD, 0) ++ | FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(fd_cnx), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "iiop_connection_from_fd connect [%d]\n", ++ GIOP_CONNECTION_GET_FD(fd_cnx)); ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(fd_cnx)); ++ ++ return fd_cnx; ++} ++ ++/* ++ * iiop_connection_server ++ * ++ * Outputs: 'server_cnx' ++ * ++ * Description: Creates a special IIOPConnection on which incoming ++ * connections come. ++ */ ++IIOPConnection * ++iiop_connection_server(void) ++{ ++ struct hostent *hent; ++ char hn_tmp[65]; ++ socklen_t n; ++ IIOPConnection *server_cnx = g_new0(IIOPConnection, 1); ++ ++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV4); ++ ++ server_cnx->is_serversock = TRUE; ++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ++ ++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server: socket_error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ server_cnx->u.ipv4.location.sin_family = AF_INET; ++ server_cnx->u.ipv4.location.sin_addr.s_addr = INADDR_ANY; ++ bind(GIOP_CONNECTION_GET_FD(server_cnx), ++ (struct sockaddr *)&server_cnx->u.ipv4.location, ++ sizeof(struct sockaddr_in)); ++ ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0) ++ | FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ n = sizeof(struct sockaddr_in); ++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx), ++ (struct sockaddr *)&server_cnx->u.ipv4.location, &n); ++ ++ gethostname(hn_tmp, sizeof(hn_tmp) - 1); ++ ++ hent = gethostbyname(hn_tmp); ++ if(hent) ++ { ++ if (strchr (hent->h_name, '.')) ++ server_cnx->u.ipv4.hostname = g_strdup(hent->h_name); ++ else ++ { ++ struct in_addr * addr = (struct in_addr *) hent->h_addr_list[0]; ++ g_assert (hent->h_length == sizeof (struct in_addr) && addr); ++ server_cnx->u.ipv4.hostname = g_strdup (inet_ntoa (*addr)); ++ } ++ } ++ else ++ server_cnx->u.ipv4.hostname = g_strdup(hn_tmp); ++ ++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5); ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx)); ++ ++ return server_cnx; ++ ++failed: ++ close(GIOP_CONNECTION_GET_FD(server_cnx)); ++ GIOP_CONNECTION(server_cnx)->fd = -1; ++ giop_connection_free(GIOP_CONNECTION(server_cnx)); ++ server_cnx = NULL; ++ /* ++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx ++ RELEASE_LOCK(server_cnx); ++ */ ++ return NULL; ++} ++ ++/* ++ * iiop_connection_server_ipv6 ++ * Outputs: 'server_cnx' ++ * ++ * Description: Create a special IIOPConnection on which incoming ++ * connections come. ++ */ ++IIOPConnection * ++iiop_connection_server_ipv6(void) ++{ ++#ifdef HAVE_IPV6 ++ struct hostent *hent, *hent2; ++ ++ char hn_tmp[65]; ++ int n; ++ IIOPConnection *server_cnx; ++ ++ g_error("IPv6 support is baroquen! (Actually just never worked)"); ++ ++ server_cnx = g_new0(IIOPConnection, 1); ++ ++ iiop_connection_init(server_cnx, GIOP_CONNECTION_SERVER, IIOP_IPV6); ++ ++ server_cnx->is_serversock = TRUE; ++ GIOP_CONNECTION(server_cnx)->fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); ++ ++ if(GIOP_CONNECTION_GET_FD(server_cnx) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_ipv6: socket_error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ server_cnx->u.ipv6.location.sin6_family = AF_INET6; ++ bind(GIOP_CONNECTION_GET_FD(server_cnx), ++ (struct sockaddr *)&server_cnx->u.ipv6.location, ++ sizeof(struct sockaddr_in6)); ++ ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFD, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFD, 0) ++ | FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ n = sizeof(struct sockaddr_in6); ++ getsockname(GIOP_CONNECTION_GET_FD(server_cnx), &server_cnx->u.ipv6.location, &n); ++ ++ gethostname(hn_tmp, sizeof(hn_tmp) - 1); ++ ++ hent = gethostbyname(hn_tmp); ++ if(hent) { ++ hent2 = gethostbyaddr(hent->h_addr, sizeof(server_cnx->u.ipv6.location.sin6_addr), AF_INET6); ++ if(hent2) ++ server_cnx->hostname = g_strdup(hent2->h_name); ++ else ++ server_cnx->hostname = g_strdup(hn_tmp); ++ } else ++ server_cnx->hostname = g_strdup(hn_tmp); ++ ++ listen(GIOP_CONNECTION_GET_FD(server_cnx), 5); ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx)); ++ ++ return server_cnx; ++ ++failed: ++ close(GIOP_CONNECTION_GET_FD(server_cnx)); ++ GIOP_CONNECTION(server_cnx)->fd = -1; ++ giop_connection_free(GIOP_CONNECTION(server_cnx)); ++ server_cnx = NULL; ++ /* ++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx ++ RELEASE_LOCK(server_cnx); ++ */ ++#endif ++ return NULL; ++} ++ ++/* ++ * iiop_connection_server_unix ++ * ++ * Outputs: 'server_cnx_unix' ++ * ++ * Side effects: Initializes 'server_cnx_unix' if not initialized. ++ * ++ * Description: Return a special IIOPConnection on which incoming connections ++ * come. If not already initialized, it creates the connection, ++ * otherwise it returns the existing one. ++ * This is ++ */ ++IIOPConnection * ++iiop_connection_server_unix(const char *sockpath) ++{ ++ IIOPConnection *server_cnx_unix; ++ ++ g_assert(sockpath && *sockpath); ++ ++ server_cnx_unix = g_new0(IIOPConnection, 1); ++ ++ iiop_connection_init(server_cnx_unix, GIOP_CONNECTION_SERVER, IIOP_USOCK); ++ ++ server_cnx_unix->is_serversock = TRUE; ++ GIOP_CONNECTION(server_cnx_unix)->fd = socket(AF_UNIX, SOCK_STREAM, 0); ++ ++ if(GIOP_CONNECTION_GET_FD(server_cnx_unix) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_server_unix: socket_error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ strcpy(server_cnx_unix->u.usock.sun_path, sockpath); ++ ++ server_cnx_unix->u.usock.sun_family = AF_UNIX; ++ if(bind(GIOP_CONNECTION_GET_FD(server_cnx_unix), ++ (struct sockaddr *)&server_cnx_unix->u.usock, ++ SUN_LEN(&server_cnx_unix->u.usock)) != 0) { ++ /* see the comment in iiop_connection_destroy switch as to why we ++ close it here. bad hack */ ++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix)); ++ GIOP_CONNECTION(server_cnx_unix)->fd = -1; ++ goto failed; ++ } ++ ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFD, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFD, 0) ++ | FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(server_cnx_unix), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ if(listen(GIOP_CONNECTION_GET_FD(server_cnx_unix), 5) != 0) ++ goto failed; ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(server_cnx_unix)); ++ iiop_unix_socket_list = g_slist_prepend(iiop_unix_socket_list, ++ server_cnx_unix); ++ ++ /* ++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix ++ RELEASE_LOCK(server_cnx_unix); ++ */ ++ ++ return server_cnx_unix; ++ ++failed: ++ close(GIOP_CONNECTION_GET_FD(server_cnx_unix)); ++ GIOP_CONNECTION(server_cnx_unix)->fd = -1; ++ giop_connection_free(GIOP_CONNECTION(server_cnx_unix)); ++ server_cnx_unix = NULL; ++ /* ++ * FIXME: GET_LOCK and DEFINE_LOCK never called for server_cnx_unix ++ RELEASE_LOCK(server_cnx_unix); ++ */ ++ return NULL; ++} ++ ++/* ++ * iiop_unlink_unix_sockets(void) ++ * ++ * Inputs: None ++ * Outputs: None ++ * ++ * Side effects: Modifies iiop_unix_socket_list ++ * Global data structures used: iiop_unix_socket_list ++ * ++ * Description: ++ * Unlinks any Unix server sockets created. ++ * Called during program termination. ++ */ ++static void ++iiop_unlink_unix_sockets(void) ++{ ++ GSList *item; ++ ++ for (item = iiop_unix_socket_list; ++ item; item = g_slist_next(item)) { ++ GIOPConnection *cnx; ++ ++ cnx = GIOP_CONNECTION(item->data); ++ if(cnx->connection_class == GIOP_CONNECTION_SERVER) ++ unlink(IIOP_CONNECTION(cnx)->u.usock.sun_path); ++ } ++ ++ if (iiop_unix_socket_list) { ++ g_slist_free(iiop_unix_socket_list); ++ iiop_unix_socket_list = NULL; ++ } ++} ++ ++/* ++ * iiop_connection_get ++ * ++ * Inputs: 'host' - the hostname (or dotted quad) of the remote host that ++ * will be connected ++ * 'port' - the port number on the above host to connect to. ++ * 'existing_only' - don't create a new connection if ++ * an existing one with the specified host:port ++ * doesn't exist. ++ * ++ * Outputs: 'cnx' - the connection to the specified host:port, or ++ * NULL upon error. ++ * ++ * Description: Returns an IIOPConnection that is connected to the ++ * specified host:port. If a connection already exists to the ++ * host:port, just returns it. Otherwise, calls ++ * 'iiop_connection_new' to create a new connection ++ * to host:port. ++ */ ++IIOPConnection * ++iiop_connection_get(const char *host, gushort port, gboolean existing_only) ++{ ++ IIOPConnection *cnx = NULL, *tmp; ++ GList *link; ++ ++ g_assert(host); ++ g_assert(port); ++ ++ GET_LOCK(giop_connection_list); ++ for(link = giop_connection_list.list; link; link = link->next) ++ { ++ tmp = IIOP_CONNECTION(link->data); ++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP) ++ continue; ++ ++ if(!GIOP_CONNECTION(tmp)->is_valid) ++ continue; ++ ++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT) ++ continue; ++ ++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_IPV4) ++ continue; ++ ++ if(!strcmp(host, tmp->u.ipv4.hostname) ++ && htons(port) == tmp->u.ipv4.location.sin_port) { ++ cnx = tmp; ++ break; ++ } ++ } ++ RELEASE_LOCK(giop_connection_list); ++ ++ if(!cnx && !existing_only) ++ cnx = iiop_connection_new(host, port); ++ ++ return cnx; ++} ++ ++ ++/* ++ * iiop_connection_new ++ * ++ * Inputs: same meanings as in 'iiop_connection_get' ++ * Outputs: 'retval' - newly created IIOPConnection ++ * ++ * Description: Allocates and initializes a new IIOPConnection, ++ * turns 'host' into an IP address, and then makes a TCP ++ * connection to host:port. Adds it to the list of active ++ * connections. ++ */ ++IIOPConnection * ++iiop_connection_new(const char *host, gushort port) ++{ ++ IIOPConnection *retval; ++ ++ g_return_val_if_fail(host != NULL && port != 0, NULL); ++ ++ retval = g_new0(IIOPConnection, 1); ++ ++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_IPV4); ++ ++ GIOP_CONNECTION(retval)->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ++ if(GIOP_CONNECTION_GET_FD(retval) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ retval->u.ipv4.hostname = g_strdup(host); ++ ++ retval->u.ipv4.location.sin_port = htons(port); ++ retval->u.ipv4.location.sin_family = AF_INET; ++ if(!inet_aton(host, &retval->u.ipv4.location.sin_addr)) ++ { ++ struct hostent *hent; ++ hent = gethostbyname(host); ++ if(!hent) { ++ /* a (char *)h_strerror(int) function would be nice here */ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: gethostbyname error: %d\n", h_errno); ++ goto failed; ++ } ++ memcpy(&retval->u.ipv4.location.sin_addr, hent->h_addr, (size_t) sizeof(retval->u.ipv4.location.sin_addr)); ++ } ++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.ipv4.location, sizeof(retval->u.ipv4.location)) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "iiop_connection_new connect [%d] to %s:%d\n", ++ GIOP_CONNECTION_GET_FD(retval), ++ host, (guint)port); ++ ++ ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ GIOP_CONNECTION(retval)->was_initiated = TRUE; ++ GIOP_CONNECTION(retval)->is_auth = TRUE; ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(retval)); ++ ++ return retval; ++ ++failed: ++ close(GIOP_CONNECTION_GET_FD(retval)); ++ GIOP_CONNECTION(retval)->fd = -1; ++ giop_connection_free(GIOP_CONNECTION(retval)); ++ return NULL; ++} ++ ++/* ++ * iiop_connection_unix_get ++ * ++ * Inputs: 'sockpath' - Of the format 'path' ++ * ++ * Outputs: 'cnx' - the connection to the specified path, or ++ * NULL upon error. ++ * ++ * Description: Returns an IIOPConnection that is connected to the ++ * specified UNIX socket, if possible. If a connection ++ * already exists, just returns it. Otherwise, ++ * calls 'iiop_connection_unix_new' to create a new ++ * connection to sockpath. ++ */ ++IIOPConnection * ++iiop_connection_unix_get(const char *sockpath, gboolean existing_only) ++{ ++ IIOPConnection *cnx = NULL, *tmp; ++ GList *link; ++ ++ GET_LOCK(giop_connection_list); ++ for(link = giop_connection_list.list; link; link = link->next) ++ { ++ tmp = IIOP_CONNECTION(link->data); ++ ++ if(GIOP_CONNECTION(tmp)->connection_type != GIOP_CONNECTION_IIOP) ++ continue; ++ ++ if(!GIOP_CONNECTION(tmp)->is_valid) ++ continue; ++ ++ if(GIOP_CONNECTION(tmp)->connection_class != GIOP_CONNECTION_CLIENT) ++ continue; ++ ++ if(IIOP_CONNECTION(tmp)->icnxtype != IIOP_USOCK) ++ continue; ++ ++ if(!strcmp(sockpath, tmp->u.usock.sun_path)) { ++ cnx = tmp; ++ break; ++ } ++ } ++ RELEASE_LOCK(giop_connection_list); ++ ++ if(!cnx && !existing_only) ++ cnx = iiop_connection_unix_new(sockpath); ++ ++ return cnx; ++} ++ ++/* ++ * iiop_connection_unix_new ++ * ++ * Inputs: ++ * ++ * Outputs: 'retval' - newly created IIOPConnection, or NULL upon error ++ * ++ * Description: Creates a connection to a UNIX socket (if possible) ++ * Adds it to the list of active connections. ++ */ ++static IIOPConnection * ++iiop_connection_unix_new(const char *sockpath) ++{ ++ IIOPConnection *retval; ++ ++ retval = g_new0(IIOPConnection, 1); ++ ++ retval->u.usock.sun_family = AF_UNIX; ++ ++ g_snprintf(retval->u.usock.sun_path, ++ sizeof(retval->u.usock.sun_path), "%s", sockpath); ++ ++ iiop_connection_init(retval, GIOP_CONNECTION_CLIENT, IIOP_USOCK); ++ ++ GIOP_CONNECTION(retval)->fd = socket(AF_UNIX, SOCK_STREAM, 0); ++ if(GIOP_CONNECTION_GET_FD(retval) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: socket_error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ if(connect(GIOP_CONNECTION_GET_FD(retval), (struct sockaddr *)&retval->u.usock, SUN_LEN(&retval->u.usock)) < 0) { ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "iiop_connection_new: connect error: %s\n", strerror(errno)); ++ goto failed; ++ } ++ ++ GIOP_CONNECTION(retval)->was_initiated = TRUE; ++ GIOP_CONNECTION(retval)->is_auth = TRUE; ++ ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFD, FD_CLOEXEC); ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_SETFL, ++ fcntl(GIOP_CONNECTION_GET_FD(retval), F_GETFL, 0) ++ | O_NONBLOCK); ++ ++ giop_connection_add_to_list(GIOP_CONNECTION(retval)); ++ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "iiop_connection_unix_new connect [%d] to %s\n", ++ GIOP_CONNECTION_GET_FD(retval), ++ sockpath); ++ ++ return retval; ++ ++failed: ++ close(GIOP_CONNECTION_GET_FD(retval)); ++ GIOP_CONNECTION(retval)->fd = -1; ++ giop_connection_free(GIOP_CONNECTION(retval)); ++ return NULL; ++} ++ ++/* ++ * iiop_connection_server_accept ++ * Inputs: 'connection' - a server IIOPConnection. ++ * ++ * Description: Performs accept(), TCP wrapper, access checking and related ++ * duties on a connection ++ */ ++int allow_severity = LOG_INFO, deny_severity = LOG_NOTICE; ++ ++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H) ++DEFINE_LOCK(tcp_wrappers_usage); ++ ++#endif ++static void ++iiop_connection_server_accept(GIOPConnection *connection) ++{ ++ struct sockaddr sock; ++ socklen_t n; ++ int newfd; ++ GIOPConnection *newcnx; ++ ++// printk("iiop_conncetion_server_accept( %d )\n", ++// GIOP_CONNECTION_GET_FD(connection)); ++ ++ n = sizeof(sock); ++ ++ switch(IIOP_CONNECTION(connection)->icnxtype) { ++ case IIOP_IPV4: sock.sa_family = AF_INET; break; ++ case IIOP_USOCK: sock.sa_family = AF_UNIX; break; ++ case IIOP_IPV6: ++#ifdef HAVE_IPV6 ++ sock.sa_family = AF_INET6; ++#endif ++ break; ++ } ++ ++ newfd = accept(GIOP_CONNECTION_GET_FD(connection), &sock, &n); ++ ++#if defined(HAVE_HOSTS_ACCESS) && defined(HAVE_TCPD_H) ++ /* tcp wrappers access checking */ ++ switch(IIOP_CONNECTION(connection)->icnxtype) { ++ case IIOP_IPV4: ++ { ++ struct request_info request; ++ ++ GET_LOCK(tcp_wrappers_usage); ++ ++ request_init(&request, RQ_DAEMON, argv0_val, RQ_FILE, newfd, 0); ++ ++ fromhost(&request); ++ if(!hosts_access(&request)) { ++ syslog(deny_severity, "[orbit] refused connect from %s", eval_client(&request)); ++ close(newfd); newfd = -1; ++ } else ++ syslog(allow_severity, "[orbit] connect from %s", eval_client(&request)); ++ ++ RELEASE_LOCK(tcp_wrappers_usage); ++ } ++ break; ++ default: ++ /* No access controls for these transports */ ++ break; ++ } ++#endif ++ ++ if(newfd >= 0) { ++ newcnx = GIOP_CONNECTION(iiop_connection_from_fd(newfd, ++ IIOP_CONNECTION(connection))); ++ GIOP_CONNECTION(newcnx)->orb_data = connection->orb_data; ++ switch(IIOP_CONNECTION(connection)->icnxtype) { ++ case IIOP_USOCK: newcnx->is_auth = TRUE; break; ++ default: ++ break; ++ } ++ } ++} ++ ++/* ++ * iiop_connection_destroy ++ * ++ * Inputs: 'iiop_connection' - an IIOPConnection to be finalized ++ * ++ * Side effects: invalidates 'iiop_connection' for use as an IIOPConnection ++ * ++ * Description: Performs the IIOP-specific parts of connection shutdown, ++ * including sending a CLOSECONNECTION message to the remote side. ++ */ ++static void ++iiop_connection_destroy(IIOPConnection *iiop_connection) ++{ ++ const GIOPMessageHeader mh = {"GIOP", {1,0}, FLAG_ENDIANNESS, ++ GIOP_CLOSECONNECTION, 0}; ++ ++ switch(iiop_connection->icnxtype) { ++ case IIOP_IPV4: ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "iiop_connection_destroy connect [%d] of %s:%d\n", ++ GIOP_CONNECTION_GET_FD(iiop_connection), ++ iiop_connection->u.ipv4.hostname, ++ ntohs(iiop_connection->u.ipv4.location.sin_port)); ++ g_free(iiop_connection->u.ipv4.hostname); ++ break; ++ case IIOP_IPV6: ++#ifdef HAVE_IPV6 ++ g_free(iiop_connection->u.ipv6.hostname); ++#else ++ g_warning("IPv6 unsupported, can't free it!"); ++#endif ++ break; ++ case IIOP_USOCK: ++ /* why do we check if fd is > 0 here? ++ the orb code tries to reuse existing socket connection points. ++ If binding to any of those fails because another process is using it, ++ we don't want to unlink the other server's socket! ++ if the bind fails, iiop_connection_server_unix closes the fd for us */ ++ if(GIOP_CONNECTION(iiop_connection)->connection_class == GIOP_CONNECTION_SERVER ++ && GIOP_CONNECTION(iiop_connection)->fd >= 0) ++ unlink(iiop_connection->u.usock.sun_path); ++ break; ++ default: ++ break; ++ } ++ ++ if(GIOP_CONNECTION_GET_FD(iiop_connection) >= 0) { ++ if(GIOP_CONNECTION(iiop_connection)->is_valid ++ && !GIOP_CONNECTION(iiop_connection)->was_initiated) ++ { ++ write(GIOP_CONNECTION_GET_FD(iiop_connection), &mh, sizeof(mh)); ++ } ++ ++ shutdown(GIOP_CONNECTION_GET_FD(iiop_connection), 2); ++ close(GIOP_CONNECTION_GET_FD(iiop_connection)); ++ GIOP_CONNECTION(iiop_connection)->fd = -1; ++ } ++} ++ ++static int giop_nloops = 0; ++ ++void giop_main_quit(void) { giop_nloops--; } ++ ++void ++giop_main(void) ++{ ++ int looplevel; ++ ++ looplevel = ++giop_nloops; ++ ++ while(giop_nloops > 0) { ++ ++ giop_main_iterate(TRUE); ++ ++ if(giop_nloops != looplevel) { ++ giop_nloops = --looplevel; ++ return; ++ } ++ } ++} ++ ++GIOPRecvBuffer * ++giop_main_next_message(gboolean blocking) ++{ ++ return giop_main_next_message_2(blocking, NULL); ++} ++ ++GIOPRecvBuffer * ++giop_main_next_message_2(gboolean blocking, ++ GIOPConnection *monitor) ++{ ++ GIOPConnection *connection; ++ GIOPRecvBuffer *recv_buffer = NULL; ++ ++ do { ++ recv_buffer = giop_received_list_pop(); ++// printk("giop_main_next_message_2 : recv_buffer = 0x%08X\n", recv_buffer); ++ if(recv_buffer) ++ break; ++ ++ connection = giop_check_connections(blocking); ++// printk("giop_main_next_message_2 : connection = 0x%08X\n", connection); ++ if(!connection) ++ { ++ return NULL; ++ } ++ ++ if(GIOP_CONNECTION_GET_FD(connection) < 0) { ++ g_assert(!"connection has -ve fd!"); ++ } ++ ++// printk("giop_main_next_message_2 : connection class = %d\n", ++// connection->connection_class); ++ if(connection->connection_class == GIOP_CONNECTION_SERVER) ++ iiop_connection_server_accept(connection); ++ else ++ recv_buffer = giop_recv_message_buffer_use(connection); ++ ++ if(monitor && !monitor->is_valid) ++ { ++ return NULL; ++ } ++ ++ } while(!recv_buffer); ++ ++ return recv_buffer; ++} ++ ++void ++giop_main_handle_connection(GIOPConnection *connection) ++{ ++ GIOPRecvBuffer *recv_buffer; ++ ++ //printk("giop_main_handle_connection\n"); ++ ++ g_return_if_fail(connection != NULL); ++ g_return_if_fail(connection->is_valid); ++ ++ if(connection->connection_class == GIOP_CONNECTION_SERVER) { ++ iiop_connection_server_accept(connection); ++ return; ++ } else ++ recv_buffer = giop_recv_message_buffer_use(connection); ++ ++ if(recv_buffer) { ++ if(IIOPIncomingMessageHandler) ++ IIOPIncomingMessageHandler(recv_buffer); ++ else ++ giop_received_list_push(recv_buffer); ++ } ++} ++ ++/* ++ * giop_main_handle_connection_exception ++ * ++ * Input: GIOPConnection *connection ++ * ++ * Output: ++ * ++ * Side effects: invalidates connection ++ * ++ * Description: ++ * When poll() or select() indicates that a file descriptor ++ * has been closed at the remote end, we must invalidate the associated ++ * GIOPConnection structure. ++ */ ++void ++giop_main_handle_connection_exception(GIOPConnection *connection) ++{ ++ g_return_if_fail(connection != NULL); ++ g_return_if_fail(connection->is_valid); ++ ++// printk("giop_main_handle_connection_exception(0x%X)\n", GIOP_CONNECTION_GET_FD(connection)); ++ ++ giop_connection_ref(connection); ++ ++ giop_connection_remove_from_list(connection); ++ ++ shutdown(GIOP_CONNECTION_GET_FD(connection), 2); ++ close(GIOP_CONNECTION_GET_FD(connection)); ++ GIOP_CONNECTION(connection)->fd = -1; ++ connection->is_valid = FALSE; ++ ++ if(connection->incoming_msg) { ++ giop_recv_buffer_unuse(connection->incoming_msg); ++ connection->incoming_msg = NULL; ++ } ++ ++ giop_connection_unref(connection); ++} ++ ++/* ++ * giop_main_iterate ++ * ++ * Input: 'blocking' - flag to indicate whether to wait for incoming ++ * messages (TRUE), or whether to return immediately if no ++ * incoming messages are available (FALSE). ++ * Output: None ++ * Description: ++ * Gets the next message into recv_buffer (see ++ * giop_main_next_message) If we have a handler for incoming ++ * messages, then pass recv_buffer to the handler (handler ++ * becomes the new owner of recv_buffer's contents). Otherwise, ++ * tosses it onto the list of received-but-unprocessed buffers. ++ * ++ * Warnings: ++ * If you don't have an IIOPIncomingMessageHandler set, you're ++ * probably really screwed in the long run. ++ */ ++void ++giop_main_iterate(gboolean blocking) ++{ ++ GIOPRecvBuffer *recv_buffer; ++ ++// printk("giop_main_iterate: blocking: %d\n", blocking); ++schedule(); ++ ++ recv_buffer = giop_main_next_message(blocking); ++ ++// printk("giop_main_iterate: recv_buffer = 0x%08X\n", recv_buffer); ++ ++ if(recv_buffer) { ++ if(IIOPIncomingMessageHandler) ++ IIOPIncomingMessageHandler(recv_buffer); ++ else ++ giop_received_list_push(recv_buffer); ++ } ++} ++ ++/* ++ * giop_check_connections ++ * ++ * Inputs: 'block_for_reply' - If no incoming data is immediately available ++ * should this routine wait for incoming data (TRUE) or return ++ * immediately (FALSE). ++ * ++ * Outputs: 'connection' - the first connection that has incoming ++ * data available for reading (supposedly a GIOP message, but ++ * could be anything). ++ * ++ * Side effects: Removes closed connections from the active list. ++ * ++ * Global data structures used: giop_connection_list ++ * ++ * Description: Does a poll or select (OS-dependant) on the list of file ++ * descriptors in giop_connection_list. ++ * ++ * If a file descriptor has been closed, call ++ * giop_connection_handle_exception() on it and (as ++ * appropriated by 'block_for_reply') either return ++ * NULL or do another poll/select. ++ * ++ * If a file descriptor has data available for ++ * reading, find the associated GIOPConnection (using ++ * giop_connection_list.fd_to_connection_mapping) and ++ * return that. ++ * ++ */ ++GIOPConnection * ++giop_check_connections(gboolean block_for_reply) ++{ ++ GIOPConnection *connection = NULL; ++ int pollret; ++ int numcnx_checks; ++ int i; ++#ifndef USE_POLL ++ fd_set selectset_rd, selectset_ex; ++ ++ struct timeval immediate_timeout = {0,0}; ++#endif ++ ++// printk("giop_check_connections\n"); ++ ++ do_read_msg: ++ ++ if(!giop_connection_list.list) ++ { ++// printk("giop_check_connections : list = NULL\n"); ++ BUG(); ++ return NULL; ++ } ++ ++#if 0 ++ giop_connection_list_recreate(); /* easiest way to get valid ++ select sets... */ ++#endif ++ ++#ifdef USE_POLL ++ numcnx_checks = giop_connection_list.pollset->len; ++#else ++ memcpy(&selectset_rd, &giop_connection_list.selectset_rd, ++ sizeof(selectset_rd)); ++ memcpy(&selectset_ex, &giop_connection_list.selectset_ex, ++ sizeof(selectset_ex)); ++ ++ numcnx_checks = giop_connection_list.max_fd+1; ++#endif ++ ++ restart: ++#ifdef USE_POLL ++ pollret = poll((struct pollfd *)giop_connection_list.pollset->data, ++ giop_connection_list.pollset->len, ++ block_for_reply?-1:0); ++ ++#if KORBIT_DEBUG_WRITING ++{ ++ int ix; ++ struct pollfd *fds = (struct pollfd *)giop_connection_list.pollset->data; ++// printk("back from poll(#fds = %d, block = %d) = %d)\n", giop_connection_list.pollset->len, block_for_reply, pollret); ++// for (ix = 0; ix < giop_connection_list.pollset->len; ix++) ++ // printk(" [fd = 0x%X, event = 0x%X, revent = 0x%X]\n", ++// fds[ix].fd, fds[ix].events, fds[ix].revents); ++ ++} ++#endif /* KORBIT_DEBUG_WRITING */ ++ ++ ++# else /* !USE_POLL */ ++ ++ { ++ pollret = select (giop_connection_list.max_fd + 1, ++ &selectset_rd, ++ NULL, &selectset_ex, ++ block_for_reply?NULL:&immediate_timeout); ++ } ++# endif /* !USE_POLL */ ++ ++// printk("giop_check_connections : pollret == %d\n", pollret); ++ if(pollret <= 0) { ++ if(pollret < 0) { ++ if(errno == EINTR) ++ goto restart; ++ else ++ g_warning("Error code from select/poll: %s", g_strerror(errno)); ++ } else ++ return NULL; ++ } ++ ++ /* Check for data to be read on the fd's. ++ Note we have to do the hangup/exception checking in a separate loop, ++ because there may be data waiting to be read on a connection that the ++ other end has closed. */ ++ for(i = 0; i < numcnx_checks; i++) { ++ struct fd_hash_elem *el; ++ ++#ifdef USE_POLL ++ struct pollfd *p = ++ &g_array_index(giop_connection_list.pollset, ++ struct pollfd, ++ i); ++ g_assert(p->fd <= giop_connection_list.max_fd); ++#ifndef __KORBIT__ ++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd]; ++#else ++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping, ++ &(p->fd)); ++ if (el) ++ connection = el->cnx; ++#endif ++ if(p->revents & POLLIN) ++ goto got_connection; ++#else ++#ifndef __KORBIT__ ++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i]; ++#else ++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping, ++ &i); ++ if (el) ++ connection = el->cnx; ++#endif ++ if (FD_ISSET(i, &selectset_rd)) { ++ goto got_connection; ++ } ++#endif ++ } ++ ++ /* Handle fd exceptions */ ++ for(i = 0; i < numcnx_checks; i++) ++ { ++ struct fd_hash_elem *el; ++#ifdef USE_POLL ++ struct pollfd *p = ++ &g_array_index(giop_connection_list.pollset, ++ struct pollfd, ++ i); ++ ++ g_assert(p->fd <= giop_connection_list.max_fd); ++ if(p->revents & (POLLHUP|POLLNVAL)) { ++#ifndef __KORBIT__ ++ connection = giop_connection_list.fd_to_connection_mapping->pdata[p->fd]; ++#else ++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping, ++ &(p->fd)); ++ if (el) ++ connection = el->cnx; ++#endif ++ giop_main_handle_connection_exception(connection); ++ } ++#else /* !USE_POLL */ ++ if(FD_ISSET(i, &selectset_ex)) { ++#ifndef __KORBIT__ ++ connection = giop_connection_list.fd_to_connection_mapping->pdata[i]; ++#else ++ el = g_hash_table_lookup(giop_connection_list.fd_to_connection_mapping, ++ &i); ++ if (el) ++ connection = el->cnx; ++#endif ++ giop_main_handle_connection_exception(connection); ++ } ++#endif /* !USE_POLL */ ++ } ++ ++ /* Only reached if we didn't find a connection to read data from */ ++ if(block_for_reply) ++ goto do_read_msg; ++ ++ got_connection: ++// printk("giop_check_connections : got connection\n"); ++ return connection; ++} ++ +diff -urN linux-2.4.1/net/korbit/IIOP/encoders.c linux-2.4.1-korbit/net/korbit/IIOP/encoders.c +--- linux-2.4.1/net/korbit/IIOP/encoders.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/encoders.c Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,46 @@ ++#include "config.h" ++#include <string.h> ++#include "IIOP.h" ++ ++ENCODER_DEC(IOP_ServiceContext) ++{ ++ APA(&mem->context_id, sizeof(mem->context_id)); ++ ENCODER_CALL(CORBA_sequence_octet, &mem->context_data); ++} ++ ++ENCODER_DEC(IOP_ServiceContextList) ++{ ++ int i; ++ ++ if(!mem) ++ { ++ APA((gpointer)giop_scratch_space, sizeof(mem->_length)); ++ return; ++ } ++ ++ APA(&mem->_length, sizeof(mem->_length)); ++ ++ for(i = 0; i < mem->_length; i++) ++ ENCODER_CALL(IOP_ServiceContext, &mem->_buffer[i]); ++} ++ ++ENCODER_DEC(CORBA_sequence_octet) ++{ ++ if(!mem) ++ { ++ APA((gpointer)giop_scratch_space, sizeof(mem->_length)); ++ return; ++ } ++ ++ APIA(&mem->_length, sizeof(mem->_length)); ++ if(mem->_length > 0) ++ AP(mem->_buffer, mem->_length); ++} ++ ++ENCODER_DEC(CORBA_char) ++{ ++ GIOP_unsigned_long len = strlen(mem) + 1; ++ ++ APIA(&len, sizeof(len)); ++ AP(mem, len); ++} +diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c +--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.c Fri Feb 2 01:23:46 2001 +@@ -0,0 +1,1443 @@ ++/* The big picture: ++ * For every outgoing request, we have to have the network-ready data ++ * somewhere in memory. ++ * ++ * Using writev, any pieces that do not need endian conversion can ++ * be written in-place. ++ * ++ * The pieces that do need endian conversion can be put into one or more ++ * buffers. ++ * ++ * WHOA WHOA newsflash ++ * Because IIOP lets the message sender specify the endianness, ++ * we do not need to do endian conversion _ever_! The receiver can do all ++ * conversions if need be, or if they are the same endianness as sender they ++ * can just pull it in right off the wire :) ++ * ++ */ ++ ++#include "config.h" ++#include "iiop-endianP.h" ++#include <string.h> ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++#include <sys/types.h> ++#include <fcntl.h> ++#include <string.h> ++ ++#ifdef HAVE_POLL ++# include <sys/poll.h> ++#else ++# include <sys/types.h> ++# include <sys/time.h> ++#endif ++#include "IIOP.h" ++#include "IIOP-private.h" ++ ++#ifdef HAVE_LIMITED_WRITEV ++#define writev g_writev ++#endif ++ ++/* ++#ifdef O_NONBLOCK ++#undef O_NONBLOCK ++#endif ++#define O_NONBLOCK 0 ++*/ ++ ++ ++/* type defs */ ++ ++#ifdef __GNUC__ ++#define PACKED __attribute__((packed)) ++#else ++#define PACKED ++#endif ++ ++/* ++ * Overlaps with struct _GIOPMessageHeader on purpose ++ * - we save time because this stuff never changes ++ */ ++struct _GIOPMessageHeaderConstants { ++ GIOP_char magic[4]; ++ GIOP_char GIOP_version[2]; ++ GIOP_octet flags; ++} PACKED; ++ ++/* functions */ ++static gint giop_recv_decode_message(GIOPRecvBuffer *buf); ++static gboolean num_on_list(GIOP_unsigned_long num, ++ const GIOP_unsigned_long *request_ids, ++ GIOP_unsigned_long req_count); ++static gint giop_recv_reply_decode_message(GIOPRecvBuffer *buf); ++static gint giop_recv_request_decode_message(GIOPRecvBuffer *buf); ++static gint giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf); ++static gint giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf); ++static GIOPRecvBuffer *giop_received_list_check_reply(GIOP_unsigned_long request_id); ++ ++#ifdef NOT_REENTRANT ++extern DEFINE_LOCK(iiop_connection_list); ++#endif ++GList *iiop_connection_list = NULL; ++ ++/* global variables */ ++char giop_scratch_space[2048]; ++ ++static const struct _GIOPMessageHeaderConstants ++giop_message_header_constants = { ++ "GIOP", ++ {1,0}, ++ FLAG_ENDIANNESS, ++}; ++ ++struct iovec ++giop_first_message_vec = {NULL, ++ sizeof(struct _GIOPMessageHeaderConstants)}; ++ ++DEFINE_LOCK(sendbufferlist); ++GSList *sendbufferlist = NULL; ++ ++DEFINE_LOCK(recvbufferlist); ++GSList *recvbufferlist = NULL; ++ ++DEFINE_LOCK(incoming_bufs); ++GList *incoming_bufs = NULL; /* List of incoming messages that had to be ++ shunted aside */ ++ ++DEFINE_LOCK(sendbuffers); ++DEFINE_LOCK(recvbuffers); ++GMemChunk *sendbuffers = NULL, *recvbuffers = NULL; ++ ++DEFINE_LOCK(request_id_counter); ++GIOP_unsigned_long request_id_counter; ++ ++#if 0 ++inline ++void giop_message_buffer_append_iovec(GIOPMessageBuffer *msgbuf, ++ const struct iovec *iovec) ++{ ++ /* g_print("Appending iovec %d bytes @ %p\n", iovec->iov_len, iovec->iov_base); */ ++ g_array_append_val(msgbuf->iovecs, *iovec); ++} ++#else ++#define giop_message_buffer_append_iovec(msgbuf, iovec) g_array_append_val((msgbuf)->iovecs, *(iovec)) ++#endif ++ ++void ++giop_message_buffer_init(void) ++{ ++ giop_first_message_vec.iov_base = (gpointer)&giop_message_header_constants; ++ INIT_LOCK(sendbufferlist); ++ INIT_LOCK(recvbufferlist); ++ request_id_counter = 1; ++ INIT_LOCK(request_id_counter); ++ ++ INIT_LOCK(sendbuffers); ++ sendbuffers = g_mem_chunk_create(GIOPSendBuffer, 2, G_ALLOC_ONLY); ++ INIT_LOCK(recvbuffers); ++ recvbuffers = g_mem_chunk_create(GIOPRecvBuffer, 2, G_ALLOC_ONLY); ++} ++ ++static void ++giop_message_buffer_new(GIOPMessageBuffer *buf) ++{ ++ buf->iovecs = g_array_new(FALSE, FALSE, sizeof(struct iovec)); ++} ++ ++#define STRUCT_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f)) ++ ++/* Send buffers only */ ++static GIOPSendBuffer * ++giop_send_buffer_new(void) ++{ ++ GIOPSendBuffer *msgbuf; ++ struct iovec firstvec; ++ ++ GET_LOCK(sendbuffers); ++ msgbuf = g_chunk_new(GIOPSendBuffer, sendbuffers); ++ RELEASE_LOCK(sendbuffers); ++ ++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf)); ++ ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), ++ &giop_first_message_vec); ++ ++ firstvec.iov_base = &(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_type); ++ firstvec.iov_len = sizeof(GIOPMessageHeader) ++ - STRUCT_OFFSET(GIOPMessageHeader, message_type); ++ GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_size = 0; ++ ++ msgbuf->indirects = g_mem_chunk_create(char[GIOP_INDIRECT_CHUNK_SIZE], ++ 2, G_ALLOC_ONLY); ++ ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), &firstvec); ++ ++ return msgbuf; ++} ++ ++gint ++giop_send_buffer_write(GIOPSendBuffer *send_buffer) ++{ ++ gulong nvecs; ++ glong res, sum, t; ++ struct iovec *curvec; ++ int fd; ++ GIOPConnection *cnx; ++ gint retval = -1; ++ ++// printf("giop_send_buffer_write\n"); ++ ++ cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection; ++ if(!cnx->is_valid) ++ return -1; ++ ++ fd = GIOP_CONNECTION_GET_FD(cnx); ++ nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len; ++ curvec = (struct iovec *)GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data; ++ ++#if defined(ORBIT_DEBUG) && 0 ++ g_print("Message of length %d looks like:\n", ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size); ++{ int i = 0; ++ for(sum = 0; i < nvecs; i++) { ++ sum += curvec[i].iov_len; ++ g_print(" [%p, %d]: %d\n", curvec[i].iov_base, curvec[i].iov_len, ++ sum); ++ } ++} ++#endif ++ ++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); ++ res = writev(fd, curvec, nvecs); ++// printk("writev wrote %d byte\n", res); ++ ++ sum = (GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader)); ++ if(res < sum) { ++ if(res < 0) { ++//printf("writev returned %d\n", res); ++ if(errno != EAGAIN) { ++ giop_main_handle_connection_exception(cnx); ++ goto out; ++ } ++ ++ res = 0; ++ } ++ ++ /* wrote 7, iovecs 3, 2, 2, 4: ++ 0 + 3 !> 7 ++ 3 + 2 !> 7 ++ 5 + 2 !> 7 ++ */ ++ ++ for(t = 0; ; t += curvec->iov_len, curvec++, nvecs--) { ++ if((t + curvec->iov_len) > res) ++ break; ++ } ++ if((res - t) > 0) { ++ curvec->iov_len -= (res - t); ++ curvec->iov_base = (gpointer)((char *)curvec->iov_base + (res - t)); ++ } ++ ++ ++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); ++ t = writev(fd, curvec, nvecs); ++ ++ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); ++ ++ if((t < 0) || ((res + t) < sum)) { ++//printf("crap, t = %d res = %d sum = %d\n", t, res, sum); ++ giop_main_handle_connection_exception(cnx); ++ goto out; ++ } ++ } ++ ++ retval = 0; ++ ++ out: ++ ++ return retval; ++} ++ ++static GIOPSendBuffer * ++giop_send_buffer_use(GIOPConnection *connection) ++{ ++ GIOPSendBuffer *retval; ++ ++ if(!connection->is_valid) ++ return NULL; ++ ++ GET_LOCK(sendbufferlist); ++ ++ if(sendbufferlist) ++ { ++ GSList *head; ++ ++ retval = sendbufferlist->data; ++ ++ head = sendbufferlist; ++ sendbufferlist = g_slist_remove_link(sendbufferlist, sendbufferlist); ++ g_slist_free_1 (head); ++ ++ g_array_set_size(GIOP_MESSAGE_BUFFER(retval)->iovecs, 2); ++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0; ++ } ++ else ++ retval = giop_send_buffer_new(); ++ ++ RELEASE_LOCK(sendbufferlist); ++ ++ giop_connection_ref(connection); ++ GIOP_MESSAGE_BUFFER(retval)->connection = connection; ++ ++ g_mem_chunk_reset(retval->indirects); ++ retval->indirect = g_chunk_new(gpointer, retval->indirects); ++#ifdef ORBIT_DEBUG ++ memset(retval->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE); ++#endif ++ retval->indirect_used = 0; ++ ++ return retval; ++} ++ ++GIOPSendBuffer * ++giop_send_reply_buffer_use(GIOPConnection *connection, ++ const IOP_ServiceContextList *service_context, ++ GIOP_unsigned_long request_id, ++ GIOPReplyStatusType reply_status) ++{ ++ GIOPSendBuffer *send_buffer; ++ ++ send_buffer = giop_send_buffer_use(connection); ++ ++ if(!send_buffer) ++ return NULL; ++ ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REPLY; ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ if(!service_context) { ++ static const GIOP_unsigned_long sc_zero_int = 0; ++ AP(&sc_zero_int, sizeof(service_context->_length)); ++ } else { ++ int i, n; ++ n = service_context->_length; ++ AP(&service_context->_length, sizeof(service_context->_length)); ++ for(i = 0; i < n; i++) { ++ int j, o; ++ CORBA_sequence_octet *seqo; ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ AP(&service_context->_buffer[i].context_id, ++ sizeof(service_context->_buffer[i].context_id)); ++ seqo = &service_context->_buffer[i].context_data; ++ o = seqo->_length; ++ AP(&seqo->_length, sizeof(GIOP_unsigned_long)); ++ for(j = 0; j < o; j++) ++ AP(seqo->_buffer, seqo->_length); ++ } ++ } ++ send_buffer->message.u.reply.request_id = request_id; ++ send_buffer->message.u.reply.reply_status = reply_status; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ AP(&send_buffer->message.u.reply.request_id, ++ sizeof(GIOP_unsigned_long)); ++ AP(&send_buffer->message.u.reply.reply_status, ++ sizeof(GIOP_unsigned_long)); ++ ++ return send_buffer; ++} ++ ++GIOPSendBuffer * ++giop_send_locate_reply_buffer_use(GIOPConnection *connection, ++ GIOP_unsigned_long request_id, ++ GIOPLocateStatusType locate_reply_status) ++{ ++ GIOPSendBuffer *send_buffer; ++ ++ send_buffer = giop_send_buffer_use(connection); ++ ++ if(!send_buffer) ++ return NULL; ++ ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREPLY; ++ ++ APIA(&request_id, sizeof(request_id)); ++ APIA(&locate_reply_status, sizeof(locate_reply_status)); ++ ++ return send_buffer; ++} ++ ++GIOPSendBuffer * ++giop_send_request_buffer_use(GIOPConnection *connection, ++ const IOP_ServiceContextList *service_context, ++ GIOP_unsigned_long request_id, ++ GIOP_boolean response_expected, ++ const struct iovec *object_key_vec, ++ const struct iovec *operation_vec, ++ const struct iovec *principal_vec) ++{ ++ GIOPSendBuffer *send_buffer; ++#if 0 ++ static const struct { ++ CORBA_unsigned_long _length; ++ char _buffer[7]; ++ } default_principal = { sizeof("nobody"), "nobody" }; ++ static const struct iovec default_principal_vec = ++ {(void *)&default_principal, ++ sizeof(CORBA_unsigned_long) + sizeof("nobody")}; ++#endif ++ ++ if (!connection) ++ return NULL; ++ if(!object_key_vec) ++ return NULL; ++ if(!operation_vec) ++ return NULL; ++ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "Sending request %s id %d to %s\n", ++ ((guchar *)operation_vec->iov_base) + 4, ++ request_id, ((guchar *)object_key_vec->iov_base) + 4); ++ ++ send_buffer = giop_send_buffer_use(connection); ++ ++ if (!send_buffer) ++ return NULL; ++ ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REQUEST; ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ if(!service_context) { ++ static const GIOP_unsigned_long sc_zero_int = 0; ++ AP(&sc_zero_int, sizeof(GIOP_unsigned_long)); ++ } else { ++ int i, n; ++ n = service_context->_length; ++ AP(&service_context->_length, sizeof(service_context->_length)); ++ for(i = 0; i < n; i++) { ++ int j, o; ++ CORBA_sequence_octet *seqo; ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ AP(&service_context->_buffer[i].context_id, ++ sizeof(service_context->_buffer[i].context_id)); ++ seqo = &service_context->_buffer[i].context_data; ++ o = seqo->_length; ++ AP(&seqo->_length, sizeof(GIOP_unsigned_long)); ++ for(j = 0; j < o; j++) ++ AP(seqo->_buffer, seqo->_length); ++ } ++ } ++ send_buffer->message.u.request.request_id = request_id; ++ send_buffer->message.u.request.response_expected = response_expected; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(GIOP_unsigned_long)); ++ AP(&send_buffer->message.u.request.request_id, ++ sizeof(GIOP_unsigned_long)); ++ AP(&send_buffer->message.u.request.response_expected, ++ sizeof(GIOP_boolean)); ++#if 0 ++ API(&response_expected, 1); ++ AP((gpointer)giop_scratch_space, 3); ++#endif ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), ++ object_key_vec); ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += ++ object_key_vec->iov_len; ++ ++ /* ++ * We can know the length at compile time - don't calculate it at runtime ++ * if we can help it :) ++ */ ++ /* ENCODER_CALL(CORBA_string, (CORBA_string *)operation); */ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), ++ operation_vec); ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += ++ operation_vec->iov_len; ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), ++ principal_vec); ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += ++ principal_vec->iov_len; ++ ++ return send_buffer; ++} ++ ++GIOPSendBuffer * ++giop_send_locate_request_buffer_use(GIOPConnection *connection, ++ GIOP_unsigned_long request_id, ++ const struct iovec *object_key_vec) ++{ ++ GIOPSendBuffer *send_buffer; ++ ++ if (!connection) ++ return NULL; ++ if (!object_key_vec) ++ return NULL; ++ ++ ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, ++ "Sending locate request id %d to %s\n", ++ request_id, ((guchar *)object_key_vec->iov_base) + 4); ++ ++ send_buffer = giop_send_buffer_use(connection); ++ ++ if (!send_buffer) ++ return NULL; ++ ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREQUEST; ++ ++ APIA(&request_id, sizeof(request_id)); ++ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), ++ object_key_vec); ++ GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += ++ object_key_vec->iov_len; ++ ++ return send_buffer; ++} ++ ++void ++giop_send_buffer_unuse(GIOPSendBuffer *send_buffer) ++{ ++ if (send_buffer == NULL) ++ return; ++ ++ giop_connection_unref(GIOP_MESSAGE_BUFFER(send_buffer)->connection); ++ ++ GET_LOCK(sendbufferlist); ++ sendbufferlist = g_slist_prepend(sendbufferlist, send_buffer); ++ RELEASE_LOCK(sendbufferlist); ++} ++ ++gulong ++giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer, ++ gulong align_for) ++{ ++ struct iovec newvec; ++ struct iovec *lastvec; ++ guint alignme; ++ gulong real_msgsize; ++ gulong align_diff; ++ ++ if(align_for < 2) return 0; ++ if(align_for > ++ MAX(sizeof(GIOP_long_long),sizeof(GIOP_long_double))) ++ align_for = MAX(sizeof(GIOP_long_long), sizeof(GIOP_long_double)); ++ ++ real_msgsize = buffer->message_header.message_size+sizeof(GIOPMessageHeader); ++ ++ alignme = (gulong)ALIGN_ADDRESS(real_msgsize, align_for); ++ ++ align_diff = alignme - real_msgsize; ++ if(align_diff > 0) ++ { ++ lastvec = (struct iovec *)(buffer->iovecs->data) ++ + buffer->iovecs->len - 1; ++ ++ if(lastvec->iov_base == giop_scratch_space) ++ { ++ newvec.iov_len = align_diff; ++ lastvec->iov_len += align_diff; ++ buffer->message_header.message_size += align_diff; ++ } ++ else ++ { ++ newvec.iov_base = (gpointer)giop_scratch_space; ++ newvec.iov_len = align_diff; ++ buffer->message_header.message_size += align_diff; ++ giop_message_buffer_append_iovec(buffer, &newvec); ++ } ++ return newvec.iov_len; ++ } ++ else ++ return 0; ++} ++ ++void ++giop_message_buffer_append_mem_a(GIOPMessageBuffer *buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length) ++{ ++ struct iovec newvec; ++ struct iovec *lastvec; ++ gint alignfor; ++ ++ alignfor = giop_message_buffer_do_alignment(buffer, mem_region_length); ++ ++ lastvec = (struct iovec *)(buffer->iovecs->data) + ++ + buffer->iovecs->len - 1; ++ ++ if((mem_region == giop_scratch_space && lastvec->iov_base == giop_scratch_space) ++ || (alignfor == 0 && (((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region)) ++ { ++ lastvec->iov_len += mem_region_length; ++ } ++ else ++ { ++ newvec.iov_base = (gpointer)mem_region; ++ newvec.iov_len = mem_region_length; ++ giop_message_buffer_append_iovec(buffer, &newvec); ++ } ++ ++ buffer->message_header.message_size += mem_region_length; ++} ++ ++void ++giop_message_buffer_append_mem(GIOPMessageBuffer *buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length) ++{ ++ struct iovec newvec; ++ struct iovec *lastvec; ++ ++ lastvec = (struct iovec *)(buffer->iovecs->data) ++ + buffer->iovecs->len - 1; ++ ++ if((mem_region == giop_scratch_space ++ && lastvec->iov_base == giop_scratch_space) ++ || ((((guchar *)lastvec->iov_base) + lastvec->iov_len) == mem_region)) ++ { ++ lastvec->iov_len += mem_region_length; ++ } ++ else ++ { ++ newvec.iov_base = (gpointer)mem_region; ++ newvec.iov_len = mem_region_length; ++ giop_message_buffer_append_iovec(buffer, &newvec); ++ } ++ ++ buffer->message_header.message_size += mem_region_length; ++} ++ ++/* I think we need a WE_WANT_NEW_CRAPPY_BUGGY_CODE ifdef here - this ++ tiny routine seems to be horribly hard to get right. ++ ++ Basically we have to paste the whole of 'mem_region' into our ++ memory chunks, possibly subdividing it up to fit it into multiple ++ 1K chunks. Because we have to return the first paste point in case ++ the client wants to manipulate it afterwards, if mem_region_length ++ >= sizeof(CORBA_unsigned_long), we also have to guarantee that the ++ pasted stuff doesn't get divided on a finer boundary than ++ sizeof(CORBA_unsigned_long). ++*/ ++gpointer ++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length) ++{ ++ gulong offset = 0, thisblock_size; ++ gpointer blockstart = NULL; ++ ++ while(offset < mem_region_length) { ++ thisblock_size = MIN(mem_region_length - offset, ++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used); ++ ++ if((thisblock_size >= sizeof(CORBA_unsigned_long)) ++ || (mem_region_length - offset) < sizeof(CORBA_unsigned_long)) { ++ if (!blockstart) ++ blockstart = ++ ((guchar*) send_buffer->indirect) + send_buffer->indirect_used; ++ ++ memcpy((guchar*)send_buffer->indirect + send_buffer->indirect_used, ++ (guchar*)mem_region + offset, thisblock_size); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), ++ (guchar*)send_buffer->indirect + ++ send_buffer->indirect_used, ++ thisblock_size); ++ offset += thisblock_size; ++ send_buffer->indirect_used += thisblock_size; ++ } ++ ++ if(send_buffer->indirect_used >= (GIOP_INDIRECT_CHUNK_SIZE - sizeof(CORBA_unsigned_long))) { ++#ifdef I_CANT_FIGURE_OUT_WHAT_THIS_LOGIC_WAS_MEANT_TO_DO ++ || (thisblock_size >= sizeof(CORBA_unsigned_long) ++ && (mem_region_length - offset) > 0)) { ++#endif ++ send_buffer->indirect_used = 0; ++ send_buffer->indirect = g_chunk_new(gpointer, ++ send_buffer->indirects); ++ } ++ } ++ ++ return blockstart; ++} ++ ++#ifdef WE_WANT_OLD_DEAD_CRAPPY_BUGGY_CODE ++gpointer ++_giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length) ++{ ++ gpointer blockstart = NULL; ++ gulong offset, new_offset; ++ ++ for(offset = new_offset = 0; new_offset < mem_region_length;) ++ { ++ new_offset = ++ MIN(mem_region_length - offset, ++ GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used); ++ ++ if((new_offset - offset) > sizeof(CORBA_unsigned_long) ++ || mem_region_length >= sizeof(CORBA_unsigned_long)) { ++ ++ if(!blockstart) ++ blockstart = send_buffer->indirect + send_buffer->indirect_used; ++ } ++ ++ memcpy(send_buffer->indirect + send_buffer->indirect_used, ++ mem_region + offset, new_offset - offset); ++ ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), ++ send_buffer->indirect + send_buffer->indirect_used, ++ new_offset - offset); ++ ++ send_buffer->indirect_used += new_offset - offset; ++ ++ offset = new_offset; ++ ++ if(new_offset >= GIOP_INDIRECT_CHUNK_SIZE) ++ { ++ send_buffer->indirect_used = 0; ++ send_buffer->indirect = g_chunk_new(gpointer, ++ send_buffer->indirects); ++#ifdef ORBIT_DEBUG ++ memset(send_buffer->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE); ++#endif ++ } ++ } ++ ++ return blockstart; ++} ++#endif ++ ++gpointer ++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *send_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length) ++{ ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), ++ mem_region_length); ++ return giop_send_buffer_append_mem_indirect(send_buffer, ++ mem_region, mem_region_length); ++} ++ ++GIOP_unsigned_long ++giop_get_request_id(void) ++{ ++ GIOP_unsigned_long retval; ++ GET_LOCK(request_id_counter); ++ retval = request_id_counter++; ++ RELEASE_LOCK(request_id_counter); ++ return retval; ++} ++ ++/**************************************************** ++ * GIOPRecvBuffer routines ++ ****************************************************/ ++ ++static GIOPRecvBuffer * ++giop_recv_buffer_new(void) ++{ ++ GIOPRecvBuffer *msgbuf; ++ ++ GET_LOCK(recvbuffers); ++ msgbuf = g_chunk_new(GIOPRecvBuffer, recvbuffers); ++ RELEASE_LOCK(recvbuffers); ++ ++ giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf)); ++ msgbuf->message_body = NULL; ++ ++ return msgbuf; ++} ++ ++void ++giop_recv_buffer_unuse(GIOPRecvBuffer *buffer) ++{ ++ if (buffer == NULL) ++ return; ++ ++ if(buffer->message_body) { ++ buffer->message_body = ((guchar *)buffer->message_body) ++ - sizeof(GIOPMessageHeader); ++ ++ g_free(buffer->message_body); ++ buffer->message_body = NULL; ++ } ++ ++ if(GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg == buffer) ++ GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg = NULL; ++ ++ giop_connection_unref(GIOP_MESSAGE_BUFFER(buffer)->connection); ++ ++ GET_LOCK(recvbufferlist); ++ recvbufferlist = g_slist_prepend(recvbufferlist, buffer); ++ RELEASE_LOCK(recvbufferlist); ++} ++ ++static GIOPRecvBuffer * ++giop_recv_buffer_use(GIOPConnection *connection) ++{ ++ GIOPRecvBuffer *retval; ++ ++ if(!connection || !connection->is_valid) ++ return NULL; ++ ++ GET_LOCK(recvbufferlist); ++ ++ if(recvbufferlist) ++ { ++ GSList *head; ++ ++ retval = recvbufferlist->data; ++ ++ head = recvbufferlist; ++ recvbufferlist = g_slist_remove_link(recvbufferlist, recvbufferlist); ++ g_slist_free_1 (head); ++ ++ GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0; ++ retval->message_body = NULL; ++ } ++ else ++ retval = giop_recv_buffer_new(); ++ ++ retval->state = GIOP_MSG_READING_HEADER; ++ retval->left_to_read = sizeof(GIOPMessageHeader); ++ ++ RELEASE_LOCK(recvbufferlist); ++ ++ giop_connection_ref(connection); ++ GIOP_MESSAGE_BUFFER(retval)->connection = connection; ++ ++ return retval; ++} ++ ++GIOPRecvBuffer * ++giop_recv_message_buffer_use(GIOPConnection *connection) ++{ ++ GIOPRecvBuffer *retval; ++ char *bptr; ++ int sysret; ++ guint message_size; ++ ++// printf("giop_recv_message_buffer_use: connection = 0x%X\n", connection); ++ ++ if(!connection || !connection->is_valid) ++ return NULL; ++ ++ if(connection->incoming_msg) ++ retval = connection->incoming_msg; ++ else { ++ retval = giop_recv_buffer_use(connection); ++ connection->incoming_msg = retval; ++ } ++ ++ if(!retval) return NULL; ++ ++ do { ++ switch(retval->state) { ++ case GIOP_MSG_READING_HEADER: ++ bptr = ((char *)&(GIOP_MESSAGE_BUFFER(retval)->message_header)); ++ bptr += sizeof(GIOP_MESSAGE_BUFFER(retval)->message_header) ++ - retval->left_to_read; ++ break; ++ case GIOP_MSG_READING_BODY: ++ bptr = retval->cur; /* Reason for not using retval->message_body: ++ See note XXX1 below */ ++ bptr += GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; ++ bptr -= retval->left_to_read; ++ break; ++ default: ++ bptr = NULL; ++ } ++ ++//printf("#1p1: READ %d bytes: errno %d state = %d\n", retval->left_to_read, errno, retval->state); ++ sysret = read(GIOP_CONNECTION_GET_FD(connection), bptr, ++ retval->left_to_read); ++ ++ if((sysret == 0) ++ || ((sysret < 0) && (errno != EAGAIN))) { ++//printf("#1: sysret = %d bptr = 0x%X errno = %d\n", sysret, bptr, errno); ++ goto errout; ++ } ++ ++ if(sysret > 0) ++ retval->left_to_read -= sysret; ++ ++ if(retval->left_to_read == 0) { ++ /* we change states here */ ++ ++ switch(retval->state) { ++ case GIOP_MSG_READING_HEADER: ++ /* Check the magic stuff */ ++ if(strncmp(GIOP_MESSAGE_BUFFER(retval)->message_header.magic, "GIOP", 4) ++ || GIOP_MESSAGE_BUFFER(retval)->message_header.GIOP_version[0] != 1) { ++//printf("#2: Not a GIOP thinger? '%s'\n", GIOP_MESSAGE_BUFFER(retval)->message_header.magic); ++ goto errout; ++ } ++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_size == 0 ++ && GIOP_MESSAGE_BUFFER(retval)->message_header.message_type != GIOP_CLOSECONNECTION) { ++// printf("Unexpected 0-length IIOP message\n"); ++ goto errout; ++ } ++ ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(retval))) { ++ CORBA_unsigned_long t = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; ++ retval->decoder = (void (*)(gpointer, gpointer, gulong))iiop_byteswap; ++ ++ iiop_byteswap((gpointer)&GIOP_MESSAGE_BUFFER(retval)->message_header.message_size, ++ (gpointer)&t, sizeof(t)); ++ } else { ++#ifdef __KERNEL__ ++ retval->decoder = (void (*)(gpointer,gpointer,gulong))__memcpy; ++#else ++ retval->decoder = (void (*)(gpointer,gpointer,gulong))memcpy; ++#endif ++ } ++ ++ message_size = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; ++ if(!connection->is_auth ++ && message_size > 131072) { ++// printf("message size is bigger than 128k (%d)\n", message_size); ++ goto errout; ++ } ++ ++ retval->message_body = g_malloc(message_size+sizeof(GIOPMessageHeader)); ++ /* XXX1 This is a lame hack to work with the fact that ++ alignment is relative to the MessageHeader, not the RequestHeader */ ++ retval->message_body = ((guchar *)retval->message_body) + sizeof(GIOPMessageHeader); ++ retval->cur = retval->message_body; ++ retval->state = GIOP_MSG_READING_BODY; ++ retval->left_to_read = message_size; ++ break; ++ case GIOP_MSG_READING_BODY: ++ if(giop_recv_decode_message(retval)) { ++//printf("giop_recv_decode_message FAILURE!\n"); ++ goto errout; ++ } ++ connection->incoming_msg = NULL; ++ retval->state = GIOP_MSG_READY; ++ break; ++ default: ++ break; ++ } ++ } else if(retval->left_to_read < 0) { ++// printf("Whoa, we overstepped the number of bytes we were supposed to read by %d\n", -retval->left_to_read); ++ goto errout; ++ } else /* retval->left_to_read > 0 */ { ++ /* couldn't read the whole piece, save it */ ++ retval = NULL; ++ } ++ } while(retval && retval->state != GIOP_MSG_READY); ++ ++ return retval; ++ ++ errout: ++ giop_recv_buffer_unuse(retval); ++ giop_main_handle_connection_exception(connection); ++ return NULL; ++} ++ ++void ++giop_received_list_push(GIOPRecvBuffer *recv_buffer) ++{ ++ GET_LOCK(incoming_bufs); ++ incoming_bufs = g_list_prepend(incoming_bufs, recv_buffer); ++ RELEASE_LOCK(incoming_bufs); ++} ++ ++GIOPRecvBuffer *giop_received_list_pop(void) ++{ ++ GList *head; ++ GIOPRecvBuffer *retval; ++ ++ GET_LOCK(incoming_bufs); ++ ++ head = incoming_bufs; ++ ++ if(!head) ++ return NULL; ++ ++ retval = head->data; ++ incoming_bufs = g_list_remove_link(incoming_bufs, head); ++ g_list_free_1 (head); ++ ++ RELEASE_LOCK(incoming_bufs); ++ ++ return retval; ++} ++ ++static GIOPRecvBuffer * ++giop_received_list_check_reply(GIOP_unsigned_long request_id) ++{ ++ GIOPRecvBuffer *retval = NULL; ++ GList *item = NULL; ++ ++ GET_LOCK(incoming_bufs); ++ ++ for(item = incoming_bufs; item; item = g_list_next(item)) ++ { ++ if(GIOP_MESSAGE_BUFFER(item->data)->message_header.message_type == GIOP_REPLY ++ && GIOP_RECV_BUFFER(item->data)->message.u.reply.request_id == request_id) { ++ retval = item->data; ++ break; ++ } ++ } ++ ++ if(retval) ++ incoming_bufs = g_list_remove(incoming_bufs, retval); ++ ++ RELEASE_LOCK(incoming_bufs); ++ ++ return retval; ++} ++ ++/** giop_recv_reply_buffer_use_multiple ++ */ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_multiple(GArray *request_ids, ++ gboolean block_for_reply) ++{ ++ return giop_recv_reply_buffer_use_multiple_2(NULL, request_ids, block_for_reply); ++} ++ ++/* here is how it will be: ++ one routine for getting next message with a specified reply ID. ++ */ ++ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx, ++ GArray *request_ids, ++ gboolean block_for_reply) ++{ ++ int i; ++ GIOPRecvBuffer *retval = NULL; ++ GSList *pushme = NULL; ++ ++ do { ++ /* ++ * We _do_ want to put this inside the loop, ++ * because we may call ourselves recursively for different request_id's ++ */ ++ for(i = 0; i < request_ids->len && !retval; i++) ++ retval = giop_received_list_check_reply(g_array_index(request_ids, GIOP_unsigned_long, i)); ++ ++ if(retval) ++ break; ++ ++ retval = giop_main_next_message_2(block_for_reply, request_cnx); ++ ++ if(retval) { ++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_REPLY) { ++ if(num_on_list(retval->message.u.reply.request_id, ++ (GIOP_unsigned_long *)request_ids->data, ++ request_ids->len)) ++ break; ++ else { ++ pushme = g_slist_prepend(pushme, retval); retval = NULL; ++ } ++ } else { ++ if(IIOPIncomingMessageHandler) ++ IIOPIncomingMessageHandler(retval); ++ else { ++ pushme = g_slist_prepend(pushme, retval); retval = NULL; ++ } ++ retval = NULL; ++ } ++ } else ++ return NULL; ++ ++ } while(!retval && block_for_reply); ++ ++ g_slist_foreach(pushme, (GFunc)giop_received_list_push, NULL); ++ g_slist_free(pushme); ++ ++ return retval; ++} ++ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id, ++ gboolean block_for_reply) ++{ ++ return giop_recv_reply_buffer_use_2(NULL, request_id, block_for_reply); ++} ++ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx, ++ GIOP_unsigned_long request_id, ++ gboolean block_for_reply) ++{ ++ GArray fakeme; ++ ++ fakeme.len = 1; ++ fakeme.data = (gpointer)&request_id; ++ ++ return giop_recv_reply_buffer_use_multiple_2(request_cnx, ++ &fakeme, ++ block_for_reply); ++} ++ ++GIOPRecvBuffer * ++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id, ++ gboolean block_for_reply) ++{ ++ GIOPRecvBuffer *retval = NULL; ++ ++ do { ++ /* ++ * We _do_ want to put this inside the loop, ++ * because we may call ourselves recursively for different request_id's ++ */ ++ retval = giop_received_list_check_reply(request_id); ++ ++ if(retval) ++ break; ++ ++ retval = giop_main_next_message_2(TRUE, NULL); ++ ++ if(retval) { ++ if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_LOCATEREPLY ++ && retval->message.u.locate_reply.request_id == request_id) ++ break; ++ else { ++ if(IIOPIncomingMessageHandler) ++ IIOPIncomingMessageHandler(retval); ++ else ++ giop_received_list_push(retval); ++ retval = NULL; ++ } ++ } else ++ return NULL; ++ } while(!retval && block_for_reply); ++ ++ return retval; ++} ++ ++static gint ++giop_recv_decode_message(GIOPRecvBuffer *buf) ++{ ++ switch(GIOP_MESSAGE_BUFFER(buf)->message_header.message_type) ++ { ++ case GIOP_REPLY: ++ return giop_recv_reply_decode_message(buf); ++ break; ++ case GIOP_REQUEST: ++ return giop_recv_request_decode_message(buf); ++ break; ++ case GIOP_LOCATEREQUEST: ++ return(giop_recv_locate_request_decode_message(buf)); ++ break; ++ case GIOP_LOCATEREPLY: ++ return(giop_recv_locate_reply_decode_message(buf)); ++ break; ++ case GIOP_CLOSECONNECTION: ++ return 0; ++ break; ++ default: ++// printf("Don't know how to decode message type %d\n", ++// GIOP_MESSAGE_BUFFER(buf)->message_header.message_type); ++ return -1; ++ } ++} ++ ++/* if(currptr+len > end || currptr + len < currptr) */ ++ ++/* This whole mess needs redoing. */ ++#define CHECK_NEW_POS(buf, requested_increment) \ ++if(!( (( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \ ++ + (requested_increment) ) \ ++ <= ( ((guchar *)GIOP_RECV_BUFFER(buf)->message_body) \ ++ + GIOP_MESSAGE_BUFFER(buf)->message_header.message_size)) \ ++ && ( ( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \ ++ + (requested_increment) ) \ ++ >= ((guchar*)GIOP_RECV_BUFFER(buf)->cur) ))) goto out; ++ ++#define NEW_POS_OUT out: return -1 ++ ++#define SAFE_ALIGN_ADDRESS(buf, amt) G_STMT_START { \ ++guchar *newval; \ ++newval = ALIGN_ADDRESS(GIOP_RECV_BUFFER(buf)->cur, amt); \ ++CHECK_NEW_POS(buf, newval-((guchar *)GIOP_RECV_BUFFER(buf)->cur)); \ ++GIOP_RECV_BUFFER(buf)->cur = newval; \ ++} G_STMT_END ++ ++#define GET_ULONG(x) G_STMT_START{ \ ++ (x) = GUINT32_SWAP_LE_BE((*(CORBA_unsigned_long *)buf->cur)); \ ++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \ ++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \ ++ }G_STMT_END ++ ++#define GET_ULONG_NC(x) G_STMT_START{ \ ++ *(x) = (*((CORBA_unsigned_long *)(buf->cur))); \ ++ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \ ++ buf->cur = ((guchar *)buf->cur) + sizeof(CORBA_unsigned_long); \ ++ }G_STMT_END ++ ++/* There be dragons in here. */ ++static gint ++giop_recv_reply_decode_message(GIOPRecvBuffer *buf) ++{ ++ /* ++ enum ReplyStatusType { ++ NO_EXCEPTION, ++ USER_EXCEPTION, ++ SYSTEM_EXCEPTION, ++ LOCATION_FORWARD ++ }; ++ ++ struct ReplyHeader { ++ IOP::ServiceContextList service_context; ++ unsigned long request_id; ++ ReplyStatusType reply_status; ++ }; ++ */ ++ int i; ++ ++ buf->message.u.reply.service_context._maximum = 0; ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) ++ { ++ GET_ULONG(buf->message.u.reply.service_context._length); ++/* XXX bad hardcoded hack until someone gives a "right answer" to how to ++solve this problem */ ++ if(buf->message.u.reply.service_context._length > 128) return -1; ++ buf->message.u.reply.service_context._buffer = ++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length); ++ ++ for(i = 0; i < buf->message.u.reply.service_context._length; i++) ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_id); ++ GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_data._length); ++ buf->message.u.reply.service_context._buffer[i].context_data._buffer = ++ buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length; ++ } ++ GET_ULONG(buf->message.u.reply.request_id); ++ GET_ULONG(buf->message.u.reply.reply_status); ++ } ++ else ++ { ++ ++ GET_ULONG_NC(&buf->message.u.reply.service_context._length); ++/* XXX bad hardcoded hack until someone gives a "right answer" to how to ++solve this problem */ ++ if(buf->message.u.reply.service_context._length > 128) return -1; ++ buf->message.u.reply.service_context._buffer = ++ g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length); ++ ++ for(i = 0; i < buf->message.u.reply.service_context._length; i++) ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(CORBA_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_id); ++ GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_data._length); ++ buf->message.u.reply.service_context._buffer[i].context_data._buffer = ++ buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.reply.service_context._buffer[i].context_data._length; ++ } ++ GET_ULONG_NC(&buf->message.u.reply.request_id); ++ GET_ULONG_NC(&buf->message.u.reply.reply_status); ++ } ++ ++#if 0 ++ g_message("[%d] Received reply %d size %d to request %d", ++ getpid(), ++ buf->message.u.reply.reply_status, ++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size, ++ buf->message.u.reply.request_id); ++#endif ++ ++ return 0; ++ ++ NEW_POS_OUT; ++} ++ ++static gint ++giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf) ++{ ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) ++ { ++ GET_ULONG(buf->message.u.locate_reply.request_id); ++ GET_ULONG(buf->message.u.locate_reply.locate_status); ++ } ++ else ++ { ++ GET_ULONG_NC(&buf->message.u.locate_reply.request_id); ++ GET_ULONG_NC(&buf->message.u.locate_reply.locate_status); ++ } ++ ++ return 0; ++ NEW_POS_OUT; ++} ++ ++static gint ++giop_recv_request_decode_message(GIOPRecvBuffer *buf) ++{ ++ GIOP_unsigned_long len; ++ int i; ++ ++ buf->message.u.request.service_context._maximum = 0; ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) ++ { ++ GET_ULONG(buf->message.u.request.service_context._length); ++ ++ /* XXX bad hardcoded hack until someone gives a "right answer" ++ to how to solve this problem */ ++ ++ if(buf->message.u.request.service_context._length > 128) return -1; ++ buf->message.u.request.service_context._buffer = ++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length); ++ ++ for(i = 0; i < buf->message.u.request.service_context._length; i++) ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_id); ++ GET_ULONG(buf->message.u.request.service_context._buffer[i].context_data._length); ++ buf->message.u.request.service_context._buffer[i].context_data._buffer = ++ buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length; ++ } ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.request.request_id); ++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur); ++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean)); ++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean); ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.request.object_key._length); ++ buf->message.u.request.object_key._buffer = buf->cur; ++ ++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length; ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(len); ++ buf->message.u.request.operation = buf->cur; ++ ++ CHECK_NEW_POS(buf, len); ++ buf->cur = ((guchar *)buf->cur) + len; ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.request.requesting_principal._length); ++ buf->message.u.request.requesting_principal._buffer = buf->cur; ++ ++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length; ++ } ++ else ++ { ++ GET_ULONG_NC(&buf->message.u.request.service_context._length); ++ ++ /* XXX bad hardcoded hack until someone gives a "right answer" ++ to how to solve this problem */ ++ if(buf->message.u.request.service_context._length > 128) return -1; ++ buf->message.u.request.service_context._buffer = ++ g_new(IOP_ServiceContext, buf->message.u.request.service_context._length); ++ ++ for(i = 0; i < buf->message.u.request.service_context._length; i++) ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_id); ++ GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_data._length); ++ buf->message.u.request.service_context._buffer[i].context_data._buffer = ++ buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.service_context._buffer[i].context_data._length; ++ } ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.request.request_id); ++ buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur); ++ CHECK_NEW_POS(buf, sizeof(GIOP_boolean)); ++ buf->cur = ((guchar *)buf->cur) + sizeof(GIOP_boolean); ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.request.object_key._length); ++ buf->message.u.request.object_key._buffer = buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.request.object_key._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.object_key._length; ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&len); ++ buf->message.u.request.operation = buf->cur; ++ CHECK_NEW_POS(buf, len); ++ buf->cur = ((guchar *)buf->cur) + len; ++ ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.request.requesting_principal._length); ++ buf->message.u.request.requesting_principal._buffer = buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.request.requesting_principal._length; ++ } ++ ++#if 0 ++ g_message("[%d] Received request %s size %d ID %d", ++ getpid(), ++ buf->message.u.request.operation, ++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size, ++ buf->message.u.request.request_id); ++#endif ++ ++ return 0; ++ ++ NEW_POS_OUT; ++} ++ ++static gint ++giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf) ++{ ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.locate_request.request_id); ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG(buf->message.u.locate_request.object_key._length); ++ buf->message.u.locate_request.object_key._buffer = buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length; ++ } ++ else ++ { ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.locate_request.request_id); ++ SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); ++ GET_ULONG_NC(&buf->message.u.locate_request.object_key._length); ++ buf->message.u.locate_request.object_key._buffer = buf->cur; ++ CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length); ++ buf->cur = ((guchar *)buf->cur) + buf->message.u.locate_request.object_key._length; ++ } ++ ++ return 0; ++ ++ NEW_POS_OUT; ++} ++ ++gboolean ++num_on_list(GIOP_unsigned_long num, ++ const GIOP_unsigned_long *request_ids, ++ GIOP_unsigned_long req_count) ++{ ++ int i; ++ for(i = 0; i < req_count; i++) ++ { ++ if(num == request_ids[i]) ++ return TRUE; ++ } ++ ++ return FALSE; ++} +diff -urN linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h +--- linux-2.4.1/net/korbit/IIOP/giop-msg-buffer.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/giop-msg-buffer.h Thu Feb 1 16:19:47 2001 +@@ -0,0 +1,228 @@ ++#ifndef GIOP_MSG_BUFFER_H ++#define GIOP_MSG_BUFFER_H 1 ++ ++#include "IIOP.h" ++/* For struct iovec */ ++#include <sys/uio.h> ++ ++typedef enum { ++ GIOP_REQUEST, ++ GIOP_REPLY, ++ GIOP_CANCELREQUEST, ++ GIOP_LOCATEREQUEST, ++ GIOP_LOCATEREPLY, ++ GIOP_CLOSECONNECTION, ++ GIOP_MESSAGEERROR, ++ GIOP_FRAGMENT ++} GIOPMsgType; ++ ++/* GIOP message header */ ++typedef struct _GIOPMessageHeader { ++ GIOP_char magic[4]; ++ GIOP_char GIOP_version[2]; ++ GIOP_octet flags; ++ ++ /* ++ * We should really use GIOPMsgType ++ * but that enum winds up being an int... ++ */ ++ GIOP_octet message_type; ++ ++ GIOP_unsigned_long message_size; ++} GIOPMessageHeader; ++ ++#define GIOP_MESSAGE_BUFFER(x) ((GIOPMessageBuffer *)x) ++typedef struct _GIOPMessageBuffer ++{ ++ /* The connection that this message will go out over... */ ++ GIOPConnection *connection; ++ ++ GArray *iovecs; ++ GIOPMessageHeader message_header; ++} GIOPMessageBuffer; ++ ++#include "../orb/iop.h" ++ ++/* GIOP_REQUEST header */ ++typedef enum { ++ GIOP_NO_EXCEPTION, ++ GIOP_USER_EXCEPTION, ++ GIOP_SYSTEM_EXCEPTION, ++ GIOP_LOCATION_FORWARD ++} GIOPReplyStatusType; ++ ++typedef struct _GIOPMessageRequest { ++ IOP_ServiceContextList service_context; ++ GIOP_unsigned_long request_id; ++ GIOP_boolean response_expected; ++ CORBA_sequence_octet object_key; ++ CORBA_char *operation; ++ CORBA_Principal requesting_principal; ++} GIOPMessageRequest; ++ ++typedef struct _GIOPMessageReply { ++ IOP_ServiceContextList service_context; ++ GIOP_unsigned_long request_id; ++ GIOPReplyStatusType reply_status; ++} GIOPMessageReply; ++ ++typedef struct _GIOPMessageCancelRequest { ++ GIOP_unsigned_long request_id; ++} GIOPMessageCancelRequest; ++ ++typedef struct _GIOPMessageLocateRequest { ++ GIOP_unsigned_long request_id; ++ CORBA_sequence_octet object_key; ++} GIOPMessageLocateRequest; ++ ++typedef enum { ++ GIOP_UNKNOWN_OBJECT, ++ GIOP_OBJECT_HERE, ++ GIOP_OBJECT_FORWARD ++} GIOPLocateStatusType; ++ ++typedef struct _GIOPMessageLocateReply { ++ GIOP_unsigned_long request_id; ++ GIOPLocateStatusType locate_status; ++} GIOPMessageLocateReply; ++ ++typedef struct _GIOPMessage ++{ ++ union { ++ GIOPMessageRequest request; ++ GIOPMessageReply reply; ++ GIOPMessageCancelRequest cancel_request; ++ GIOPMessageLocateRequest locate_request; ++ GIOPMessageLocateReply locate_reply; ++ } u; ++} GIOPMessage; ++ ++typedef enum { ++ GIOP_MSG_READING_HEADER, ++ GIOP_MSG_READING_BODY, ++ GIOP_MSG_READY ++} GIOPMessageBufferState; ++ ++#define GIOP_SEND_BUFFER(x) ((GIOPSendBuffer *)x) ++typedef struct _GIOPSendBuffer ++{ ++ GIOPMessageBuffer message_buffer; ++ ++ gpointer indirect; ++ ++ GMemChunk *indirects; /* Request buffers only (at present) */ ++ gulong indirect_used; ++ ++ GIOPMessage message; ++ CORBA_unsigned_long scontext_tmp; ++} GIOPSendBuffer; ++ ++#define GIOP_RECV_BUFFER(x) ((GIOPRecvBuffer *)x) ++typedef struct _GIOPRecvBuffer ++{ ++ GIOPMessageBuffer message_buffer; ++ GIOPMessage message; ++ ++ gpointer message_body; ++ gpointer cur; ++ ++ void (*decoder)(gpointer dest, gpointer src, gulong len); ++ ++ GIOPMessageBufferState state; ++ gint left_to_read; ++} GIOPRecvBuffer; ++ ++/* This function needs to be called before useful things happen */ ++void giop_message_buffer_init(void); ++ ++gint giop_send_buffer_write(GIOPSendBuffer *request_buffer); ++ ++void ++giop_message_buffer_append_mem_a(GIOPMessageBuffer *request_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length); ++void ++giop_message_buffer_append_mem(GIOPMessageBuffer *request_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length); ++ ++/* ++ * This copies the value into a request-specific buffer before ++ * adding it to the list ++ */ ++gpointer ++giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *request_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length); ++gpointer ++giop_send_buffer_append_mem_indirect(GIOPSendBuffer *request_buffer, ++ gconstpointer mem_region, ++ gulong mem_region_length); ++ ++GIOPSendBuffer * ++giop_send_request_buffer_use(GIOPConnection *connection, ++ const IOP_ServiceContextList *service_context, ++ GIOP_unsigned_long request_id, ++ GIOP_boolean response_expected, ++ const struct iovec *object_key_vec, ++ const struct iovec *operation_vec, ++ const struct iovec *principal_vec); ++GIOPSendBuffer * ++giop_send_reply_buffer_use(GIOPConnection *connection, ++ const IOP_ServiceContextList *service_context, ++ GIOP_unsigned_long request_id, ++ GIOPReplyStatusType reply_status); ++GIOPSendBuffer * ++giop_send_locate_request_buffer_use(GIOPConnection *connection, ++ GIOP_unsigned_long request_id, ++ const struct iovec *object_key_vec); ++GIOPSendBuffer * ++giop_send_locate_reply_buffer_use(GIOPConnection *connection, ++ GIOP_unsigned_long request_id, ++ GIOPLocateStatusType reply_status); ++ ++void giop_send_buffer_unuse(GIOPSendBuffer *send_buffer); ++ ++GIOP_unsigned_long giop_get_request_id(void); ++ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use(GIOP_unsigned_long request_id, ++ gboolean block_for_reply); ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx, ++ GIOP_unsigned_long request_id, ++ gboolean block_for_reply); ++ ++/* For DII - hands back the first received request matching an id on the list */ ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_multiple(GArray *request_ids, ++ gboolean block_for_reply); ++GIOPRecvBuffer * ++giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx, ++ GArray *request_ids, ++ gboolean block_for_reply); ++ ++GIOPRecvBuffer * ++giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id, ++ gboolean block_for_reply); ++ ++/* ++ * For server-side use. It's the responsibility of the caller to do ++ * any select()ion desired ++ */ ++GIOPRecvBuffer * ++giop_recv_message_buffer_use(GIOPConnection *connection); ++ ++void giop_recv_buffer_unuse(GIOPRecvBuffer *buffer); ++ ++/* ++ * This is used for sending (and recving, if we ever ++ * get zero-copy receives implemented) alignment bytes ++ */ ++extern char giop_scratch_space[2048]; ++gulong giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer, ++ gulong align_for); ++ ++#define giop_msg_conversion_needed(msgbuf) (conversion_needed(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.flags & 1)) ++ ++#endif /* GIOP_MSG_BUFFER_H */ +diff -urN linux-2.4.1/net/korbit/IIOP/iiop-encoders.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h +--- linux-2.4.1/net/korbit/IIOP/iiop-encoders.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-encoders.h Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,25 @@ ++#ifndef ENCODERS_H ++#define ENCODERS_H 1 ++ ++#define ENCODER_DEC(typename) \ ++void giop_encoder_##typename##(GIOPSendBuffer *send_buffer, \ ++ const typename *mem) ++ ++#define ENCODER_CALL(typename, mem) \ ++giop_encoder_##typename##(send_buffer, mem) ++ ++#define AP(m, l) giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), m, l) ++#define APA(m, l) giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), m, l) ++ ++#define API(m, l) giop_send_buffer_append_mem_indirect(send_buffer, m, l) ++#define APIA(m, l) giop_send_buffer_append_mem_indirect_a(send_buffer, m, l) ++ ++ENCODER_DEC(IOP_ServiceContext); ++ENCODER_DEC(IOP_ServiceContextList); ++ENCODER_DEC(CORBA_sequence_octet); ++ENCODER_DEC(CORBA_Principal); ++#define giop_encoder_CORBA_Principal(rb, mem) \ ++ giop_encoder_CORBA_sequence_octet(rb, mem) ++ENCODER_DEC(CORBA_char); ++ ++#endif /* ENCODERS_H */ +diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.c linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c +--- linux-2.4.1/net/korbit/IIOP/iiop-endian.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.c Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,12 @@ ++#define IIOP_DO_NOT_INLINE_IIOP_BYTESWAP ++#include "iiop-endian.h" ++ ++void iiop_byteswap(guchar *outdata, ++ const guchar *data, ++ gulong datalen) ++{ ++ const guchar *source_ptr = data; ++ guchar *dest_ptr = (guchar *)outdata + datalen - 1; ++ while(dest_ptr >= outdata) ++ *dest_ptr-- = *source_ptr++; ++} +diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endian.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h +--- linux-2.4.1/net/korbit/IIOP/iiop-endian.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endian.h Thu Feb 1 11:46:51 2001 +@@ -0,0 +1,42 @@ ++#ifndef IIOP_ENDIAN_H ++#define IIOP_ENDIAN_H 1 ++ ++#include <glib.h> ++ ++#if G_BYTE_ORDER == G_BIG_ENDIAN ++ ++# define FLAG_ENDIANNESS FLAG_BIG_ENDIAN ++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_BIG_ENDIAN) ++ ++#elif G_BYTE_ORDER == G_LITTLE_ENDIAN ++ ++# define FLAG_ENDIANNESS FLAG_LITTLE_ENDIAN ++# define conversion_needed(to_endianness) ((to_endianness)!=FLAG_LITTLE_ENDIAN) ++ ++#else ++ ++#error "Unsupported endianness on this system." ++ ++#endif ++ ++#define FLAG_BIG_ENDIAN 0 ++#define FLAG_LITTLE_ENDIAN 1 ++ ++/* This is also defined in IIOP-types.c */ ++void iiop_byteswap(guchar *outdata, ++ const guchar *data, ++ gulong datalen); ++ ++#if defined(G_CAN_INLINE) && !defined(IIOP_DO_NOT_INLINE_IIOP_BYTESWAP) ++G_INLINE_FUNC void iiop_byteswap(guchar *outdata, ++ const guchar *data, ++ gulong datalen) ++{ ++ const guchar *source_ptr = data; ++ guchar *dest_ptr = outdata + datalen - 1; ++ while(dest_ptr >= outdata) ++ *dest_ptr-- = *source_ptr++; ++} ++#endif ++ ++#endif +diff -urN linux-2.4.1/net/korbit/IIOP/iiop-endianP.h linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h +--- linux-2.4.1/net/korbit/IIOP/iiop-endianP.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/IIOP/iiop-endianP.h Thu Feb 1 16:19:47 2001 +@@ -0,0 +1,11 @@ ++#ifndef IIOP_ENDIANP_H ++#define IIOP_ENDIANP_H 1 ++ ++/* This is pretty much "here" */ ++ ++#include "config.h" ++#include "IIOP.h" ++ ++#include "iiop-endian.h" ++ ++#endif /* !IIOP_ENDIANP_H */ +diff -urN linux-2.4.1/net/korbit/Makefile linux-2.4.1-korbit/net/korbit/Makefile +--- linux-2.4.1/net/korbit/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/Makefile Thu Feb 1 15:57:33 2001 +@@ -0,0 +1,22 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := korbit.o ++ ++subdir-y := kglib orb IIOP ORBitutil modules ++subdir-m := modules ++ ++obj-y := kglib/kglib.o orb/orblib.o IIOP/IIOPlib.o ORBitutil/ORBitutillib.o exported_symbols.o ++ ++export-objs := exported_symbols.o ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I./include -I./kglib -I./ORBitutil -nostdinc ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Entries linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries +--- linux-2.4.1/net/korbit/ORBitutil/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Entries Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,13 @@ ++/Makefile/1.4/Thu Feb 1 09:46:52 2001// ++/basic_types.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/compat.c/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/compat.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/orbit-os-config.h/1.2/Thu Feb 1 09:46:52 2001// ++/os-feature-alloca.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/os-specifics.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/thread-safety.c/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/thread-safety.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/trace.c/1.2/Thu Feb 1 09:46:52 2001// ++/trace.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++/util.h/1.1.1.1/Thu Feb 1 09:46:52 2001// ++D +diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Repository linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository +--- linux-2.4.1/net/korbit/ORBitutil/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Repository Thu Feb 1 11:46:51 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/ORBitutil +diff -urN linux-2.4.1/net/korbit/ORBitutil/CVS/Root linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root +--- linux-2.4.1/net/korbit/ORBitutil/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/CVS/Root Thu Feb 1 11:46:51 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/ORBitutil/Makefile linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile +--- linux-2.4.1/net/korbit/ORBitutil/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/Makefile Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,17 @@ ++# ++# Makefile for KORBit/ORBitutil ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .o file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := ORBitutillib.o ++ ++#obj-m := $(O_TARGET) ++obj-y := compat.o thread-safety.o trace.o ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.1/net/korbit/ORBitutil/basic_types.h linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h +--- linux-2.4.1/net/korbit/ORBitutil/basic_types.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/basic_types.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,46 @@ ++#ifndef BASIC_TYPES_H ++#define BASIC_TYPES_H 1 ++ ++#include <glib.h> ++ ++typedef gint16 CORBA_short; ++typedef gint32 CORBA_long; ++typedef guint16 CORBA_unsigned_short; ++typedef guint32 CORBA_unsigned_long; ++typedef gfloat CORBA_float; ++typedef gdouble CORBA_double; ++typedef char CORBA_char; ++typedef guchar CORBA_boolean; ++typedef guchar CORBA_octet; ++typedef gdouble CORBA_long_double; ++typedef guint16 CORBA_wchar; /* I'm not sure what size a wchar is supposed to be */ ++ ++/* Just a peeve */ ++typedef CORBA_char GIOP_char; ++typedef CORBA_wchar GIOP_wchar; ++typedef CORBA_short GIOP_short; ++typedef CORBA_long GIOP_long; ++typedef CORBA_unsigned_short GIOP_unsigned_short; ++typedef CORBA_unsigned_long GIOP_unsigned_long; ++typedef CORBA_octet GIOP_octet; ++typedef CORBA_long GIOP_enum; ++typedef CORBA_boolean GIOP_boolean; ++typedef CORBA_float GIOP_float; ++typedef CORBA_double GIOP_double; ++typedef CORBA_long_double GIOP_long_double; ++ ++#ifdef G_HAVE_GINT64 ++#define HAVE_CORBA_LONG_LONG ++/* According to the spec, these two are optional. We support them if we can. */ ++typedef gint64 CORBA_long_long; ++typedef guint64 CORBA_unsigned_long_long; ++typedef CORBA_long_long GIOP_long_long; ++typedef CORBA_unsigned_long_long GIOP_unsigned_long_long; ++#else ++#warning "" ++#warning "You don't G_HAVE_GINT64 defined in glib." ++#warning "Please make sure you don't have an old glibconfig.h lying around." ++#warning "" ++#endif ++ ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.c linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c +--- linux-2.4.1/net/korbit/ORBitutil/compat.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.c Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,43 @@ ++#include "config.h" ++#include "util.h" ++ ++#define MAX_IOVS 16 ++ ++int g_writev(int fd, const struct iovec * vector, size_t count) ++{ ++ int retval = 0; ++ ++ while(count > MAX_IOVS) { ++ retval += writev(fd, vector, MAX_IOVS); ++ vector += MAX_IOVS; count -= MAX_IOVS; ++ } ++ ++ return writev(fd, vector, count) + retval; ++} ++ ++#ifndef HAVE_INET_ATON ++#include <netinet/in.h> ++#include <string.h> ++int inet_aton(const char *cp, struct in_addr *inp) ++{ ++ union { ++ unsigned int n; ++ char parts[4]; ++ } u; ++ int a=0,b=0,c=0,d=0, i; ++ ++ i = sscanf(cp, "%d.%d.%d.%d%*s", &a, &b, &c, &d); ++ ++ if(i != 4) ++ return 0; ++ ++ u.parts[0] = a; ++ u.parts[1] = b; ++ u.parts[2] = c; ++ u.parts[3] = d; ++ ++ inp->s_addr = u.n; ++ ++ return 1; ++} ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/compat.h linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h +--- linux-2.4.1/net/korbit/ORBitutil/compat.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/compat.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,8 @@ ++#ifndef ORBITUTIL_COMPAT_H ++#define ORBITUTIL_COMPAT_H 1 ++#include <sys/types.h> ++#include <sys/uio.h> ++ ++int g_writev(int fd, const struct iovec * vector, size_t count); ++ ++#endif /*#define ORBITUTIL_COMPAT_H 1 */ +diff -urN linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h +--- linux-2.4.1/net/korbit/ORBitutil/orbit-os-config.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/orbit-os-config.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,8 @@ ++#ifndef OS_CONFIG_H ++#define OS_CONFIG_H 1 ++ ++#ifndef __KORBIT__ ++#define ORBIT_HAVE_ALLOCA_H 1 ++#endif ++ ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h +--- linux-2.4.1/net/korbit/ORBitutil/os-feature-alloca.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-feature-alloca.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,26 @@ ++#ifndef OS_FEATURE_ALLOCA_H ++#define OS_FEATURE_ALLOCA_H 1 ++ ++# if ORBIT_HAVE_ALLOCA_H ++# include <alloca.h> ++# endif ++ ++# include <string.h> ++ ++# if defined(__GNUC__) ++ ++# if defined(__STRICT_ANSI__) ++# define alloca __builtin_alloca ++# endif ++ ++# elif !(ORBIT_HAVE_ALLOCA_H) ++ ++# if defined(_AIX) ++ #pragma alloca ++# elif !defined(alloca) /* predefined by HP cc +Olibcalls */ ++char *alloca (); ++# endif ++ ++# endif /* __GNUC__ etc. */ ++ ++#endif /* OS_FEATURE_ALLOCA_H */ +diff -urN linux-2.4.1/net/korbit/ORBitutil/os-specifics.h linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h +--- linux-2.4.1/net/korbit/ORBitutil/os-specifics.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/os-specifics.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,12 @@ ++#ifndef ORBITUTIL_OS_SPECIFICS_H ++#define ORBITUTIL_OS_SPECIFICS_H 1 ++ ++#include <ORBitutil/orbit-os-config.h> ++ ++#include <ORBitutil/os-feature-alloca.h> ++ ++/* This file should be a bunch of #ifdef's to #include the ++ os-<osname>.h for the current OS. It is intended to abstract the ++ gunkiness necessary to get some OS's to build ORBit properly. */ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.c linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c +--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.c Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,19 @@ ++#include "util.h" ++ ++#ifdef NOT_REENTRANT ++#include <pthread.h> ++ ++pthread_key_t thread_data; ++ ++void init_thread_data(void) __attribute__ ((constructor)); ++ ++void init_thread_data(void) ++{ ++ pthread_key_create(&thread_data, NULL); ++} ++ ++#else ++ ++gpointer prog_data = NULL; ++ ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/thread-safety.h linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h +--- linux-2.4.1/net/korbit/ORBitutil/thread-safety.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/thread-safety.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,36 @@ ++#ifndef THREAD_SAFETY_H ++#define THREAD_SAFETY_H 1 ++ ++#ifdef NOT_REENTRANT ++ ++#include <pthread.h> ++ ++#define DEFINE_LOCK(x) pthread_mutex_t x##_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ++#define INIT_LOCK(x) /* We use static initialization, see above */ ++#define GET_LOCK(x) pthread_mutex_lock(&x##_lock) ++#define RELEASE_LOCK(x) pthread_mutex_unlock(&x##_lock) ++#define PARAM_LOCK(x) pthread_mutex_t x##_lock ++#define LOCK_NAME(x) x##_lock ++#define EXTERN_LOCK(x) extern pthread_mutex_t x##_lock ++extern pthread_key_t thread_data; ++#define GET_THREAD_DATA() pthread_getspecific(thread_data) ++#define SET_THREAD_DATA(x) pthread_setspecific(thread_data, (x)) ++ ++#else ++ ++/* stupid work around ANSI & empty semicolons. */ ++#define DEFINE_LOCK(x) ++#define INIT_LOCK(x) ++#define GET_LOCK(x) ++#define RELEASE_LOCK(x) ++#define PARAM_LOCK(x) gpointer x##_lock ++#define LOCK_NAME(x) NULL ++#define EXTERN_LOCK(x) ++ ++extern gpointer prog_data; ++#define GET_THREAD_DATA() prog_data ++#define SET_THREAD_DATA(x) (prog_data = (x)) ++ ++#endif ++ ++#endif /* THREAD_SAFETY_H */ +diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.c linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c +--- linux-2.4.1/net/korbit/ORBitutil/trace.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.c Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,94 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * ++ */ ++ ++#include <stdio.h> ++#include <stdarg.h> ++ ++#include "trace.h" ++ ++/* ++ * The function to call to handle trace messages, or NULL to use the default ++ * of printing to stderr. ++ */ ++#ifdef ORBIT_DEBUG ++static int (* TraceCallback)(char *, va_list)=NULL; ++static int TraceModules=0; ++static ORBit_TraceLevel TraceMaxLevel=0; ++ ++const char *ORBit_Trace_levellist[] = { ++ "ALERT ", ++ "CRITICAL", ++ "ERROR ", ++ "WARNING ", ++ "NOTICE ", ++ "INFO ", ++ "DEBUG " ++}; ++ ++void ORBit_Trace_setCallback(int (*cbf)(char *, va_list)) ++{ ++ TraceCallback=cbf; ++} ++ ++int (*ORBit_Trace_getCallback(void))(char *, va_list) ++{ ++ return(TraceCallback); ++} ++ ++void ORBit_Trace_setModules(int modules) ++{ ++ TraceModules=modules; ++} ++ ++void ORBit_Trace_setLevel(ORBit_TraceLevel level) ++{ ++ TraceMaxLevel=level; ++} ++ ++int ORBit_Trace(ORBit_TraceModule module, ORBit_TraceLevel level, char *fmt, ...) ++{ ++ va_list args; ++ ++ if(!BitTest(TraceModules, module)) ++ return 0; ++ if(TraceMaxLevel < level) ++ return 0; ++ ++ va_start(args, fmt); ++ if(TraceCallback!=NULL) ++ return((*TraceCallback)(fmt, args)); ++ ++#ifdef __KORBIT__ ++ printf("[%s]: ", ORBit_Trace_levellist[level]); ++ ++ printf("%s", g_strdup_vprintf(fmt, args)); ++ return 0; // breaks semantics, but return value is never used ++#else /* !__KORBIT__ */ ++ fprintf(stderr, "[%s]: ", ORBit_Trace_levellist[level]); ++ ++ return vfprintf(stderr, fmt, args); ++#endif /* !__KORBIT__ */ ++} ++#endif +diff -urN linux-2.4.1/net/korbit/ORBitutil/trace.h linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h +--- linux-2.4.1/net/korbit/ORBitutil/trace.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/trace.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,68 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * ++ */ ++ ++#ifndef _ORBIT_TRACE_H_ ++#define _ORBIT_TRACE_H_ ++ ++#include <stdarg.h> ++#include "util.h" ++ ++typedef enum { ++ TraceMod_ORB, ++ TraceMod_CDR, ++ TraceMod_IIOP, ++ TraceMod_TC, ++ TraceMod_IR, ++ TraceMod_User=32 ++} ORBit_TraceModule; ++ ++typedef enum { ++ TraceLevel_Alert=0, ++ TraceLevel_Critical, ++ TraceLevel_Error, ++ TraceLevel_Warning, ++ TraceLevel_Notice, ++ TraceLevel_Info, ++ TraceLevel_Debug ++} ORBit_TraceLevel; ++ ++extern const char *ORBit_Trace_levellist[]; ++ ++#ifdef ORBIT_DEBUG ++extern void ORBit_Trace_setCallback(int (*)(char *, va_list)); ++extern int (*ORBit_Trace_getCallback(void))(char *, va_list); ++extern void ORBit_Trace_setModules(int); ++extern void ORBit_Trace_setLevel(ORBit_TraceLevel); ++extern int ORBit_Trace(ORBit_TraceModule, ORBit_TraceLevel, char *, ...); ++#else ++#define ORBit_Trace_setCallback(x) ++#define ORBit_Trace_getCallback() NULL ++#define ORBit_Trace_setModules(x) ++#define ORBit_Trace_setLevel(x) ++#define ORBit_Trace(module,level,fmt,args...) ++#endif ++ ++ ++#endif /* !_ORBIT_TRACE_H_ */ +diff -urN linux-2.4.1/net/korbit/ORBitutil/util.h linux-2.4.1-korbit/net/korbit/ORBitutil/util.h +--- linux-2.4.1/net/korbit/ORBitutil/util.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/ORBitutil/util.h Thu Feb 1 11:46:52 2001 +@@ -0,0 +1,35 @@ ++#ifndef UTIL_H ++#define UTIL_H 1 ++ ++#include <glib.h> ++ ++#define ORBIT_DEBUG 1 ++ ++#ifdef ORBIT_DEBUG ++#define ORBIT_DEBUG_NOTE(x) (x) ++#else ++#define ORBIT_DEBUG_NOTE(x) ++#endif ++ ++ ++#define BitTest(f, bit) ((f) & (1<<(bit))) ++#define BitSet(f, bit) ((f) |= (1<<(bit))) ++#define BitClr(f, bit) ((f) &= ~(1<<(bit))) ++/* Align an address upward to a boundary, expressed as a number of bytes. ++ E.g. align to an 8-byte boundary with argument of 8. */ ++ ++/* ++ * (this + boundary - 1) ++ * & ++ * ~(boundary - 1) ++ */ ++ ++#define ALIGN_ADDRESS(this, boundary) \ ++ ((gpointer)((( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))))) ++ ++#include <ORBitutil/thread-safety.h> ++#include <ORBitutil/trace.h> ++#include <ORBitutil/compat.h> ++#include <ORBitutil/os-specifics.h> ++ ++#endif +diff -urN linux-2.4.1/net/korbit/config.h linux-2.4.1-korbit/net/korbit/config.h +--- linux-2.4.1/net/korbit/config.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/config.h Thu Feb 1 11:46:49 2001 +@@ -0,0 +1,73 @@ ++ ++/* Define if you have alloca, as a function or macro. */ ++#define HAVE_ALLOCA 1 ++ ++#define HAVE_ATEXIT 1 ++#define NO_SYS_SIGLIST 1 /* reduce dependencies */ ++#define NO_SYS_ERRLIST 1 /* reduce dependencies */ ++ ++/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ ++/* #define HAVE_ALLOCA_H 1 */ ++ ++/* Define if you have the vprintf function. */ ++#define HAVE_VPRINTF 1 ++ ++/* Define if you have the ANSI C header files. */ ++#define STDC_HEADERS 1 ++ ++#define HAVE_INET_ATON 1 ++/* #undef ORBIT_SERIAL */ ++ ++/* Define to 'int' if it isn't defined in the header files. */ ++/* #undef socklen_t */ ++ ++#define ALIGNOF_CORBA_BOOLEAN 1 ++#define ALIGNOF_CORBA_CHAR 1 ++#define ALIGNOF_CORBA_DOUBLE 4 ++#define ALIGNOF_CORBA_FLOAT 4 ++#define ALIGNOF_CORBA_LONG 4 ++#define ALIGNOF_CORBA_LONG_DOUBLE 4 ++#define ALIGNOF_CORBA_LONG_LONG 4 ++#define ALIGNOF_CORBA_OCTET 1 ++#define ALIGNOF_CORBA_SHORT 2 ++#define ALIGNOF_CORBA_STRUCT 1 ++#define ALIGNOF_CORBA_UNSIGNED_LONG 4 ++#define ALIGNOF_CORBA_UNSIGNED_LONG_LONG 4 ++#define ALIGNOF_CORBA_UNSIGNED_SHORT 2 ++#define ALIGNOF_CORBA_WCHAR 2 ++#define ALIGNOF_CORBA_POINTER 4 ++ ++/* TCP wrappers */ ++#define HAVE_TCPD_H 1 ++ ++#ifdef HAVE_ALLOCA_H ++#include <alloca.h> ++#endif ++ ++/* Define if you have the basename function. */ ++#define HAVE_BASENAME 1 ++ ++/* Define if you have the poll function. */ ++#define HAVE_POLL 1 ++#define I_WANT_POLL 1 ++ ++/* Define if you have the <endian.h> header file. */ ++#define HAVE_ENDIAN_H 1 ++ ++/* Define if you have the <fcntl.h> header file. */ ++#define HAVE_FCNTL_H 1 ++ ++/* Define if you have the <stddef.h> header file. */ ++#define HAVE_STDDEF_H 1 ++ ++/* Define if you have the <sys/poll.h> header file. */ ++#define HAVE_SYS_POLL_H 1 ++ ++/* Define if you have the <tcpd.h> header file. */ ++#define HAVE_TCPD_H 1 ++ ++/* Define if you have the <unistd.h> header file. */ ++#define HAVE_UNISTD_H 1 ++ ++/* Define if you have the <wchar.h> header file. */ ++#define HAVE_WCHAR_H 1 +diff -urN linux-2.4.1/net/korbit/exported_symbols.c linux-2.4.1-korbit/net/korbit/exported_symbols.c +--- linux-2.4.1/net/korbit/exported_symbols.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/exported_symbols.c Thu Feb 1 11:46:49 2001 +@@ -0,0 +1,93 @@ ++/* ++ * #include whatever it takes to get the EXPORT_SYMBOL macro, and ++ * whatever header files from korbit (for things that are being ++ * exported. ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include "errno.h" ++#include "orb/orbit.h" ++ ++/* ++ * Stuff that's good to export ++ */ ++EXPORT_SYMBOL(errno); ++ ++/* ++ * kglib exports... ++ */ ++EXPORT_SYMBOL(g_malloc0); ++EXPORT_SYMBOL(g_free); ++EXPORT_SYMBOL(g_snprintf); ++ ++/* ++ * Mainline CORBA symbols. ++ */ ++EXPORT_SYMBOL(CORBA_exception_init); ++EXPORT_SYMBOL(CORBA_ORB_init); ++EXPORT_SYMBOL(CORBA_ORB_resolve_initial_references); ++EXPORT_SYMBOL(CORBA_ORB_object_to_string); ++EXPORT_SYMBOL(CORBA_free); ++EXPORT_SYMBOL(CORBA_ORB_run); ++EXPORT_SYMBOL(CORBA_Object_release); ++EXPORT_SYMBOL(CORBA_Object_duplicate); ++EXPORT_SYMBOL(CORBA_octet_allocbuf); ++EXPORT_SYMBOL(CORBA_exception_set); ++EXPORT_SYMBOL(CORBA_string__free); ++EXPORT_SYMBOL(CORBA_ORB_string_to_object); ++EXPORT_SYMBOL(CORBA_string_alloc); ++EXPORT_SYMBOL(CORBA_exception_set_system); ++ ++/* ++ * ORBIT Specific symbols to export ++ */ ++EXPORT_SYMBOL(ORBit_TypeCode_epv); ++EXPORT_SYMBOL(ORBit_send_system_exception); ++EXPORT_SYMBOL(ORBit_register_class); ++EXPORT_SYMBOL(ORBit_marshal_object); ++EXPORT_SYMBOL(ORBit_alloc); ++EXPORT_SYMBOL(ORBit_free); ++EXPORT_SYMBOL(ORBit_send_user_exception); ++EXPORT_SYMBOL(ORBit_delete_profiles); ++EXPORT_SYMBOL(ORBit_demarshal_object); ++EXPORT_SYMBOL(_ORBit_object_get_connection); ++EXPORT_SYMBOL(ORBit_handle_exception); ++EXPORT_SYMBOL(ORBit_object_get_forwarded_connection); ++EXPORT_SYMBOL(ORBit_default_principal_iovec); ++EXPORT_SYMBOL(ORBit_demarshal_IOR); ++ ++/* ++ * CORBA giop functions ++ */ ++EXPORT_SYMBOL(giop_send_buffer_write); ++EXPORT_SYMBOL(giop_send_buffer_unuse); ++EXPORT_SYMBOL(giop_message_buffer_do_alignment); ++EXPORT_SYMBOL(giop_message_buffer_append_mem); ++EXPORT_SYMBOL(giop_send_reply_buffer_use); ++EXPORT_SYMBOL(giop_send_request_buffer_use); ++EXPORT_SYMBOL(giop_recv_buffer_unuse); ++EXPORT_SYMBOL(giop_recv_reply_buffer_use_2); ++ ++/* ++ * POA Symbols. ++ */ ++EXPORT_SYMBOL(PortableServer_POAManager_activate); ++EXPORT_SYMBOL(PortableServer_POA_activate_object_with_id); ++EXPORT_SYMBOL(PortableServer_POA_servant_to_reference); ++EXPORT_SYMBOL(PortableServer_POA_deactivate_object); ++EXPORT_SYMBOL(PortableServer_POA__get_the_POAManager); ++EXPORT_SYMBOL(PortableServer_ServantBase__init); ++EXPORT_SYMBOL(PortableServer_ServantBase__fini); ++EXPORT_SYMBOL(PortableServer_POA_reference_to_servant); ++EXPORT_SYMBOL(PortableServer_POA_servant_to_id); ++EXPORT_SYMBOL(PortableServer_POA_activate_object); ++EXPORT_SYMBOL(PortableServer_POA_reference_to_id); ++ ++/* ++ * TC Stuff (whatever that is) ++ */ ++EXPORT_SYMBOL(TC_octet_struct); ++EXPORT_SYMBOL(TC_long_struct); ++EXPORT_SYMBOL(TC_ulong_struct); ++EXPORT_SYMBOL(TC_short_struct); ++EXPORT_SYMBOL(TC_string_struct); +diff -urN linux-2.4.1/net/korbit/include/.cvsignore linux-2.4.1-korbit/net/korbit/include/.cvsignore +--- linux-2.4.1/net/korbit/include/.cvsignore Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/.cvsignore Thu Feb 1 11:46:53 2001 +@@ -0,0 +1 @@ ++stdarg.h +diff -urN linux-2.4.1/net/korbit/include/CVS/Entries linux-2.4.1-korbit/net/korbit/include/CVS/Entries +--- linux-2.4.1/net/korbit/include/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,24 @@ ++/.cvsignore/1.1/Thu Feb 1 09:46:53 2001// ++/alloca.h/1.3/Thu Feb 1 09:46:53 2001// ++/assert.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/ctype.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/dirent.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/errno.h/1.2/Thu Feb 1 09:46:53 2001// ++/fcntl.h/1.3/Thu Feb 1 09:46:53 2001// ++/host_list.h/1.7/Thu Feb 1 09:46:53 2001// ++/limits.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/locale.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/math.h/1.2/Thu Feb 1 09:46:53 2001// ++/netdb.h/1.17/Thu Feb 1 09:46:53 2001// ++/pwd.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/signal.h/1.1.1.1/Thu Feb 1 09:46:53 2001// ++/stdarg.h/1.3/Thu Feb 1 09:46:54 2001// ++/stddef.h/1.1.1.1/Thu Feb 1 09:46:54 2001// ++/stdio.h/1.19/Thu Feb 1 09:46:54 2001// ++/stdlib.h/1.4/Thu Feb 1 09:46:54 2001// ++/string.h/1.3/Thu Feb 1 09:46:54 2001// ++/syslog.h/1.1.1.1/Thu Feb 1 09:46:54 2001// ++/time.h/1.1.1.1/Thu Feb 1 09:46:54 2001// ++/unistd.h/1.3/Thu Feb 1 09:46:54 2001// ++/utime.h/1.1.1.1/Thu Feb 1 09:46:54 2001// ++D +diff -urN linux-2.4.1/net/korbit/include/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log +--- linux-2.4.1/net/korbit/include/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/CVS/Entries.Log Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,3 @@ ++A D/arpa//// ++A D/netinet//// ++A D/sys//// +diff -urN linux-2.4.1/net/korbit/include/CVS/Repository linux-2.4.1-korbit/net/korbit/include/CVS/Repository +--- linux-2.4.1/net/korbit/include/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/CVS/Repository Thu Feb 1 11:46:53 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/include +diff -urN linux-2.4.1/net/korbit/include/CVS/Root linux-2.4.1-korbit/net/korbit/include/CVS/Root +--- linux-2.4.1/net/korbit/include/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/CVS/Root Thu Feb 1 11:46:53 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/include/alloca.h linux-2.4.1-korbit/net/korbit/include/alloca.h +--- linux-2.4.1/net/korbit/include/alloca.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/alloca.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,6 @@ ++#ifndef __KORBIT_ALLOCA_H__ ++#define __KORBIT_ALLOCA_H__ ++ ++#include <stdlib.h> ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Entries linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries +--- linux-2.4.1/net/korbit/include/arpa/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Entries Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,2 @@ ++/inet.h/1.4/Thu Feb 1 09:46:54 2001// ++D +diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Repository linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository +--- linux-2.4.1/net/korbit/include/arpa/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Repository Thu Feb 1 11:46:54 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/include/arpa +diff -urN linux-2.4.1/net/korbit/include/arpa/CVS/Root linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root +--- linux-2.4.1/net/korbit/include/arpa/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/arpa/CVS/Root Thu Feb 1 11:46:54 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/include/arpa/inet.h linux-2.4.1-korbit/net/korbit/include/arpa/inet.h +--- linux-2.4.1/net/korbit/include/arpa/inet.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/arpa/inet.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,50 @@ ++#ifndef __KORBIT_ARPA_INET_H__ ++#define __KORBIT_ARPA_INET_H__ ++ ++#include <linux/inet.h> ++#include <linux/in.h> ++ ++static inline char* inet_ntoa(struct in_addr in) ++{ ++ return in_ntoa(in.s_addr); ++} ++ ++static inline int inet_aton(const char *cp, struct in_addr *inp) ++{ ++ unsigned long l; ++ unsigned int val; ++ int i; ++ ++ if (!cp || !inp) ++ return 0; ++ ++ l = 0; ++ for (i = 0; i < 4; i++) ++ { ++ l <<= 8; ++ if (*cp != '\0') ++ { ++ val = 0; ++ while (*cp != '\0' && *cp != '.') ++ { ++ if (*cp < '0' || '9' < *cp) ++ return 0; ++ ++ val *= 10; ++ val += *cp - '0'; ++ cp++; ++ } ++ if (val > 255) ++ return 0; ++ ++ l |= val; ++ if (*cp != '\0') ++ cp++; ++ } ++ } ++ inp->s_addr = htonl(l); ++ ++ return 1; ++} ++ ++#endif /* __KORBIT_ARPA_INET_H__ */ +diff -urN linux-2.4.1/net/korbit/include/assert.h linux-2.4.1-korbit/net/korbit/include/assert.h +--- linux-2.4.1/net/korbit/include/assert.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/assert.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_ASSERT_H__ ++#define __KORBIT_ASSERT_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/ctype.h linux-2.4.1-korbit/net/korbit/include/ctype.h +--- linux-2.4.1/net/korbit/include/ctype.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/ctype.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,4 @@ ++#ifndef __KORBIT_CTYPE_H__ ++#define __KORBIT_CTYPE_H__ ++#include <linux/ctype.h> ++#endif +diff -urN linux-2.4.1/net/korbit/include/dirent.h linux-2.4.1-korbit/net/korbit/include/dirent.h +--- linux-2.4.1/net/korbit/include/dirent.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/dirent.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_DIRENT_H__ ++#define __KORBIT_DIRENT_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/errno.h linux-2.4.1-korbit/net/korbit/include/errno.h +--- linux-2.4.1/net/korbit/include/errno.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/errno.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,9 @@ ++#ifndef __KORBIT_ERRNO_H__ ++#define __KORBIT_ERRNO_H__ ++ ++#include <asm/errno.h> ++ ++#define errno korbit_errno ++extern int korbit_errno; ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/fcntl.h linux-2.4.1-korbit/net/korbit/include/fcntl.h +--- linux-2.4.1/net/korbit/include/fcntl.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/fcntl.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,49 @@ ++#ifndef __KORBIT_FCNTL_H__ ++#define __KORBIT_FCNTL_H__ ++ ++#include <linux/mm.h> ++#include <linux/file.h> ++#include <linux/smp_lock.h> ++ ++#include <asm/fcntl.h> ++ ++#include <stdio.h> ++ ++#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC) ++ ++static inline int fcntl(int fd, int cmd, long arg) ++{ ++ struct file *filp = fd2file(fd); ++ long err = -EINVAL; ++ ++ switch (cmd) ++ { ++ case F_SETFD: ++ case F_GETFD: ++ err = 0; ++ break; ++ case F_GETFL: ++ if (filp) ++ err = filp->f_flags; ++ break; ++ case F_SETFL: ++ if (filp) ++ { ++ lock_kernel(); ++ ++ /* required for strict SunOS emulation */ ++ if (O_NONBLOCK != O_NDELAY) ++ if (arg & O_NDELAY) ++ arg |= O_NONBLOCK; ++ ++ filp->f_flags = (arg & SETFL_MASK) | ++ (filp->f_flags & ~SETFL_MASK); ++ err = 0; ++ unlock_kernel(); ++ } ++ break; ++ } ++ return err; ++} ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/host_list.h linux-2.4.1-korbit/net/korbit/include/host_list.h +--- linux-2.4.1/net/korbit/include/host_list.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/host_list.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,24 @@ ++/* ++ * A statically-allocated list of Hostnames<->IPv4 addresses. ++ */ ++#ifndef __KORBIT_HOST_LIST_H ++#define __KORBIT_HOST_LIST_H ++ ++static struct { ++ char *name; ++ char *IP; ++} host_table[] = { ++ {"redefine.dyndns.org", "206.221.225.140"}, ++ {"csil-sunb4.cs.uiuc.edu", "128.174.243.204"}, ++ {"kazoo.cs.uiuc.edu", "128.174.237.133"}, ++ {"opus0.cs.uiuc.edu", "128.174.236.20"}, ++ {"wakeland-56.flexabit.net", "64.198.239.56"}, ++ {"es-dcl-border1.cso.uiuc.edu", "127.0.0.1"}, ++ {"es-dcl-border1", "127.0.0.1"} ++// {"es-dcl-border1.cso.uiuc.edu", "130.126.112.222"}, ++// {"es-dcl-border1", "130.126.112.222"} ++}; ++ ++#define __MAX_STATIC_NAMES (sizeof(host_table) / sizeof(host_table[0])) ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/limits.h linux-2.4.1-korbit/net/korbit/include/limits.h +--- linux-2.4.1/net/korbit/include/limits.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/limits.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,7 @@ ++#ifndef __KORBIT_LIMITS_H__ ++#define __KORBIT_LIMITS_H__ ++ ++#include <linux/limits.h> ++#include <linux/kernel.h> ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/locale.h linux-2.4.1-korbit/net/korbit/include/locale.h +--- linux-2.4.1/net/korbit/include/locale.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/locale.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_LOCALE_H__ ++#define __KORBIT_LOCALE_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/math.h linux-2.4.1-korbit/net/korbit/include/math.h +--- linux-2.4.1/net/korbit/include/math.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/math.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,16 @@ ++#ifndef __KORBIT_MATH_H__ ++#define __KORBIT_MATH_H__ ++ ++#include <asm/page.h> ++ ++static inline double pow(double x, double y) { ++ double Q = 1.0; ++ if (y < 0) ++ BUG(); ++/* return 1.0/pow(x,-y);*/ ++ while (y-- > 0) ++ Q *= x; ++ return Q; ++} ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/netdb.h linux-2.4.1-korbit/net/korbit/include/netdb.h +--- linux-2.4.1/net/korbit/include/netdb.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/netdb.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,197 @@ ++#ifndef __KORBIT_NETDB_H__ ++#define __KORBIT_NETDB_H__ ++ ++#include <sys/socket.h> ++#include <linux/in.h> ++#include <arpa/inet.h> ++#include "host_list.h" ++ ++#define h_errno 0 ++/* static int h_errno; */ ++ ++/* Description of data base entry for a single host. */ ++struct hostent ++{ ++ char *h_name; /* Official name of host. */ ++ char **h_aliases; /* Alias list. */ ++ int h_addrtype; /* Host address type. */ ++ socklen_t h_length; /* Length of address. */ ++ char **h_addr_list; /* List of addresses from name server. */ ++#define h_addr h_addr_list[0] /* Address, for backward compatibility. */ ++}; ++ ++/* Is this defined somewhere else? */ ++/*struct in_addr { ++ __uint32_t s_addr; ++};*/ ++ ++/* ++ * Set h_errno? ++ * #define HOST_NOT_FOUND 1 ++ * #define TRY_AGAIN 2 ++ * #define NO_RECOVERY 3 ++ * #define NO_DATA 4 ++ */ ++static inline struct hostent *gethostbyname (char *host) ++{ ++ int c; ++ static struct in_addr tmp_in; ++ static struct hostent ret_host; ++ static char *aliases[2]; ++ static char *addrs[2]; ++ ++ if (host == NULL) ++ { ++ printf ("** gethostbyname() Error: Got NULL parameter! **\n"); ++ return (NULL); ++ } ++ ++ /* ++ * The actual lookup. ++ */ ++ for (c = 0; c < __MAX_STATIC_NAMES; c++) ++ { ++ if (host_table[c].name && strncmp (host, host_table[c].name, strlen(host_table[c].name)) == 0) ++ { ++/* printf ("Name '%s' found at position %d!\n", argv[1], c);*/ ++/* printf ("IP address is: '%s'.\n", IPs[c]);*/ ++ break; ++ } ++ } ++ ++ if (c == __MAX_STATIC_NAMES) ++ { ++ /* Host not found, return NULL. */ ++ return (NULL); ++ } ++ /* else, names[c] is gold! */ ++ ++ /* make a new hostent, ret_host */ ++ ++ ret_host.h_addrtype = AF_INET; ++ ret_host.h_aliases = aliases; ++ aliases[0] = host_table[c].name; ++ aliases[1] = NULL; ++ ret_host.h_name = host_table[c].name; ++ if (!inet_aton (host_table[c].IP, &tmp_in)) ++ { ++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n"); ++ return (NULL); ++ } ++ ret_host.h_addr_list = addrs; ++ addrs[0] = (char *)&tmp_in.s_addr; ++ addrs[1] = NULL; ++ ret_host.h_length = sizeof (tmp_in.s_addr); ++ return (&ret_host); ++} /* End gethostbyname(). */ ++ ++/* ++ * TODO: getpeername(), gethostbyaddr(), getsockname(), gethostname() ++ * Everything from here-on has been untested (in userland). Buyer beware. ++ */ ++static inline struct hostent *gethostbyaddr (const char *addr, int len, int type) ++{ ++ struct in_addr tin; ++ char *inp_addr; ++ int c; ++ static struct hostent ret_host; ++ static char *aliases[1]; ++ static char *addrs[2]; ++ static struct in_addr tmp_in; ++ ++ ++ if ((type != AF_INET) || (len != 4)) ++ { ++ printf ("** gethostbyaddr Error: Don't know how to deal with non-AF_INET addresses! **\n"); ++ return (NULL); ++ } ++ ++ tin.s_addr = *((__u32 *)addr); ++ inp_addr = inet_ntoa (tin); ++ if (inp_addr == NULL) ++ { ++ /* We got some invalid input, baby. */ ++ return (NULL); ++ ++ } ++ ++ /* ++ * The actual lookup. ++ */ ++ for (c = 0; c < __MAX_STATIC_NAMES; c++) ++ { ++ if (host_table[c].IP && strncmp (inp_addr, host_table[c].IP, strlen(host_table[c].IP)) == 0) ++ { ++ break; ++ } ++ } ++ ++ if (c == __MAX_STATIC_NAMES) ++ { ++ /* Host not found, return NULL. */ ++ return (NULL); ++ } ++ /* else, host_table[c].IP is gold! */ ++ ++ ret_host.h_addrtype = AF_INET; ++ ret_host.h_aliases = aliases; ++ aliases[0] = NULL; ++ ret_host.h_name = host_table[c].name; ++ if (!inet_aton (host_table[c].IP, &tmp_in)) ++ { ++ printf ("** gethostbyname() Error: Invalid IP address in table! **\n"); ++ return (NULL); ++ } ++ ret_host.h_addr_list = addrs; ++ addrs[0] = (char *)&tmp_in.s_addr; ++ addrs[1] = NULL; ++ ret_host.h_length = sizeof (tmp_in.s_addr); ++ return (&ret_host); ++} /* End gethostbyaddr(). */ ++ ++/* ++ * If successful, return 0. Else, return -1 and set errno. ++ * Errors: ++ * EBADF The argument s is not a valid file descriptor. ++ * ++ * ENOMEM ++ * There was insufficient memory available for the opera- ++ * tion to complete. ++ * ++ * ENOSR There were insufficient STREAMS resources available ++ * for the operation to complete. ++ * ++ * ENOTSOCK ++ * The argument s is not a socket. ++ */ ++static inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen) ++{ ++ struct socket *sock = fd2sock(s); ++ ++ if (sock == NULL) ++ return -1; ++ ++ /* ++ * getname() wants an 'int *' for the length, will it by this ++ * 'socklen_t *' business? (even though it is just an 'int *'?). ++ */ ++ if (sock->ops->getname(sock, name, namelen, 0) == 0) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} /* End getsockname(). */ ++ ++static inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen) ++{ ++ struct socket *sock = fd2sock(s); ++ ++ if (sock == NULL) ++ return -1; ++ ++ if (sock->ops->getname(sock, name, namelen, 1) == 0) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} /* End getpeername(). */ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Entries linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries +--- linux-2.4.1/net/korbit/include/netinet/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Entries Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,2 @@ ++/in.h/1.1.1.1/Thu Feb 1 09:46:55 2001// ++D +diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Repository linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository +--- linux-2.4.1/net/korbit/include/netinet/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Repository Thu Feb 1 11:46:55 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/include/netinet +diff -urN linux-2.4.1/net/korbit/include/netinet/CVS/Root linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root +--- linux-2.4.1/net/korbit/include/netinet/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/netinet/CVS/Root Thu Feb 1 11:46:55 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/include/netinet/in.h linux-2.4.1-korbit/net/korbit/include/netinet/in.h +--- linux-2.4.1/net/korbit/include/netinet/in.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/netinet/in.h Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,5 @@ ++#ifndef __KORBIT_NETINET_IN_H__ ++#define __KORBIT_NETINET_IN_H__ ++#include <linux/socket.h> ++#include <linux/in.h> ++#endif +diff -urN linux-2.4.1/net/korbit/include/pwd.h linux-2.4.1-korbit/net/korbit/include/pwd.h +--- linux-2.4.1/net/korbit/include/pwd.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/pwd.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_PWD_H__ ++#define __KORBIT_PWD_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/signal.h linux-2.4.1-korbit/net/korbit/include/signal.h +--- linux-2.4.1/net/korbit/include/signal.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/signal.h Thu Feb 1 11:46:53 2001 +@@ -0,0 +1,6 @@ ++#ifndef __KORBIT_SIGNAL_H__ ++#define __KORBIT_SIGNAL_H__ ++ ++#include <asm/signal.h> ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/stdarg.h linux-2.4.1-korbit/net/korbit/include/stdarg.h +--- linux-2.4.1/net/korbit/include/stdarg.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/stdarg.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,13 @@ ++#ifndef __KORBIT_STDARG_H__ ++#define __KORBIT_STDARG_H__ ++ ++#define ANDY 1 ++ ++#if FREDRIK ++#include "/usr/lib/gcc-lib/i386-glibc21-linux/egcs-2.91.66/include/stdarg.h" ++#elif CHRIS ++#include "/usr/lib/gcc-lib/i586-mandrake-linux/egcs-2.91.66/include/stdarg.h" ++#elif ANDY ++#include "/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h" ++#endif ++#endif +diff -urN linux-2.4.1/net/korbit/include/stddef.h linux-2.4.1-korbit/net/korbit/include/stddef.h +--- linux-2.4.1/net/korbit/include/stddef.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/stddef.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_STDDEF_H__ ++#define __KORBIT_STDDEF_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/stdio.h linux-2.4.1-korbit/net/korbit/include/stdio.h +--- linux-2.4.1/net/korbit/include/stdio.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/stdio.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,402 @@ ++#ifndef __KORBIT_STDIO_H__ ++#define __KORBIT_STDIO_H__ ++ ++#include <asm/segment.h> ++#include <asm/uaccess.h> ++#include <linux/smp_lock.h> ++#include <linux/kernel.h> ++#include <linux/fs.h> ++#include <linux/sched.h> ++#include <linux/uio.h> ++#include <linux/dcache.h> ++#include <linux/file.h> ++#include <linux/highuid.h> ++#include <sys/socket.h> ++ ++#include <errno.h> ++ ++#define KORBIT_DEBUG_WRITING 0 ++ ++ ++#define printf(format,args...) printk(format,##args) ++#define fflush(x) ++ ++#define SEEK_SET 0 /* Seek from beginning of file. */ ++#define SEEK_CUR 1 /* Seek from current position. */ ++#define SEEK_END 2 /* Seek from end of file. */ ++ ++static inline int unlink(const char *pathname) { ++ printf("KERNEL UNLINK('%s') CALLED!\n", pathname); ++ return -1; ++} ++ ++static inline struct file *fd2file(int fd) { ++ if (fd & 1) /* can't convert a socket! */ ++ return NULL; ++ ++ return (struct file *)(-(fd & ~1)); ++} ++ ++static inline int open(const char *filename, int flags, int mode) { ++ struct file *RetVal = filp_open(filename, flags, mode); ++ if (IS_ERR(RetVal)) ++ { ++ errno = PTR_ERR(RetVal); ++ return -1; ++ } ++ return -(int)RetVal; ++} ++ ++static inline int creat(const char *filename, mode_t mode) ++{ ++ return open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode); ++} ++ ++static inline int lseek(int fd, long offset, int whence) ++{ ++ if ((fd & 1) == 1) ++ { ++ printk("KERNEL FSEEK() CALLED ON SOCKET!\n"); ++ return -1; ++ } ++ else ++ { ++ struct file *F = fd2file(fd); ++ loff_t (*fn)(struct file *, loff_t, int); ++ int retval = -1; ++ ++ if (whence <= 2) ++ { ++ fn = default_llseek; ++ if (F->f_op && F->f_op->llseek) ++ fn = F->f_op->llseek; ++ ++ lock_kernel(); ++ retval = fn(F, offset, whence); ++ unlock_kernel(); ++ } ++ if (retval < 0) ++ { ++ errno = -retval; ++ retval = -1; ++ } ++ return retval; ++ } ++} ++ ++ ++asmlinkage long sys_newstat(char * filename, struct stat * statbuf); ++static inline int stat(char *filename, struct stat *buf) ++{ ++ mm_segment_t oldfs; ++ int retval; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ retval = sys_newstat(filename, buf); ++ set_fs(oldfs); ++ if (retval < 0) ++ { ++ errno = -retval; ++ retval = -1; ++ } ++ return retval; ++} ++ ++asmlinkage long sys_newlstat(char * filename, struct stat * statbuf); ++static inline int lstat(char *filename, struct stat *buf) ++{ ++ mm_segment_t oldfs; ++ int retval; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ retval = sys_newlstat(filename, buf); ++ set_fs(oldfs); ++ if (retval < 0) ++ { ++ errno = -retval; ++ retval = -1; ++ } ++ return retval; ++} ++ ++ ++static inline int do_revalidate(struct dentry *dentry) ++{ ++ struct inode * inode = dentry->d_inode; ++ if (inode->i_op && inode->i_op->revalidate) ++ return inode->i_op->revalidate(dentry); ++ return 0; ++} ++ ++ ++static inline int cp_new_stat(struct inode * inode, struct stat * statbuf) ++{ ++ struct stat tmp; ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ tmp.st_dev = kdev_t_to_nr(inode->i_dev); ++ tmp.st_ino = inode->i_ino; ++ tmp.st_mode = inode->i_mode; ++ tmp.st_nlink = inode->i_nlink; ++ SET_STAT_UID(tmp, inode->i_uid); ++ SET_STAT_GID(tmp, inode->i_gid); ++ tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); ++#if BITS_PER_LONG == 32 ++ if (inode->i_size > 0x7fffffff) ++ return -EOVERFLOW; ++ else ++#endif ++ { ++ tmp.st_size = inode->i_size; ++ tmp.st_atime = inode->i_atime; ++ tmp.st_mtime = inode->i_mtime; ++ tmp.st_ctime = inode->i_ctime; ++ ++ tmp.st_blocks = inode->i_blocks; ++ tmp.st_blksize = inode->i_blksize; ++ ++ memcpy(statbuf, &tmp, sizeof(tmp)); ++ return 0; ++ } ++} ++ ++ ++static inline int fstat(int fd, struct stat *buf) ++{ ++ if ((fd & 1) == 1) ++ { ++ printk("TODO : FSTAT FOR SOCKETS, DO WE WANT THIS?\n"); ++ errno = EBADF; ++ return -1; ++ } ++ else ++ { ++ struct file *file = fd2file(fd); ++ struct dentry *dentry; ++ int retval = -EBADF; ++ ++ if (file) ++ { ++ dentry = file->f_dentry; ++ retval = do_revalidate(dentry); ++ ++ if (!retval) ++ retval = cp_new_stat(dentry->d_inode, buf); ++ } ++ if (retval < 0) ++ { ++ errno = -retval; ++ retval = -1; ++ } ++ return retval; ++ } ++} ++ ++ ++asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz); ++static inline int readlink(const char *path, char *buf, size_t bufsiz) ++{ ++ int retval; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ retval = sys_readlink(path, buf, bufsiz); ++ set_fs(oldfs); ++ if (retval < 0) ++ { ++ errno = -retval; ++ retval = -1; ++ } ++ return retval; ++} ++ ++ ++static inline int read(int fd, void *buffer, size_t count) { ++ if ((fd & 1) == 1) ++ { ++ struct socket *sock = fd2sock(fd); ++ struct iovec iov; ++ struct msghdr msg; ++ mm_segment_t oldfs; ++ int flags = 0; ++ int RetVal; ++ ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_flags = 0; ++ iov.iov_base = buffer; ++ iov.iov_len = count; ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ RetVal = sock_recvmsg(sock, &msg, count, flags); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++ else ++ { ++ struct file *F = fd2file(fd); ++ mm_segment_t oldfs; ++ int RetVal; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ RetVal = F->f_op->read(F, buffer, count, &F->f_pos); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++} ++ ++static inline int write(int fd, const void *buffer, size_t count) { ++ if ((fd & 1) == 1) ++ { ++ struct socket *sock = fd2sock(fd); ++ struct iovec iov; ++ struct msghdr msg; ++ mm_segment_t oldfs; ++ int RetVal; ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_flags = MSG_NOSIGNAL; ++ if (sock->type == SOCK_SEQPACKET) ++ msg.msg_flags |= MSG_EOR; ++ iov.iov_base = (void *)buffer; ++ iov.iov_len = count; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ RetVal = sock_sendmsg(sock, &msg, count); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++ else ++ { ++ struct file *F = fd2file(fd); ++ mm_segment_t oldfs; ++ int RetVal; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ RetVal = F->f_op->write(F, buffer, count, &F->f_pos); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++} ++ ++static inline int writev(int fd, const struct iovec *vector, int count) { ++#ifndef DONT_USE_SIMPLE_WRITEV ++ int i, amount = 0; ++#if KORBIT_DEBUG_WRITING ++ printk("writev (fd = 0x%X, vec=0x%p, count = %d)\n", fd, vector, count); ++#endif ++ for (i = 0; i < count; i++) { ++ char *Buf = vector[i].iov_base; ++ int Amount = vector[i].iov_len; ++ while (Amount > 0) { ++ int A = write(fd, Buf, Amount); ++//#if KORBIT_DEBUG_WRITING ++if (A < Amount) ++ printk(" write(fd = 0x%X, buf = 0x%p, size = 0x%X) " ++ "= 0x%X errno = 0x%X\n", fd, Buf, Amount, A, errno); ++//#endif ++ Amount -= A; ++ amount += A; ++ Buf += A; ++ if (Amount > 0) schedule(); // Behave somewhat nicely... ++ } ++ } ++ ++#if KORBIT_DEBUG_WRITING ++ printk("writev returning 0x%X[%d]\n", amount, amount); ++#endif ++ return amount; ++ ++#else ++ if ((fd & 1) == 1) ++ { ++ struct socket *sock = fd2sock(fd); ++ struct msghdr msg; ++ mm_segment_t oldfs; ++ int i, RetVal; ++ size_t tot_len = 0; ++ ++ for (i = 0; i < count; i++) ++ tot_len += vector[i].iov_len; ++ ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ msg.msg_iov = (struct iovec *)vector; ++ msg.msg_iovlen = count; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ if (sock->type == SOCK_SEQPACKET) ++ msg.msg_flags |= MSG_EOR; ++ ++ oldfs = get_fs(); set_fs(KERNEL_DS); ++ RetVal = sock_sendmsg(sock, &msg, tot_len); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++ else ++ { ++ struct file *F = fd2file(fd); ++ mm_segment_t oldfs; ++ int RetVal; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ RetVal = F->f_op->writev(F, vector, (unsigned)count, &F->f_pos); ++ set_fs(oldfs); ++ if (RetVal < 0) ++ { ++ errno = -RetVal; ++ RetVal = -1; ++ } ++ return RetVal; ++ } ++#endif ++} ++ ++static inline int close(int fd) { ++ int err = 0; ++ if ((fd & 1) == 1) { ++ struct socket *sock = fd2sock(fd); ++ sock_release(sock); ++ } else { ++ struct file *file = fd2file(fd); ++ fput(file); ++ } ++ return err; ++} ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/stdlib.h linux-2.4.1-korbit/net/korbit/include/stdlib.h +--- linux-2.4.1/net/korbit/include/stdlib.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/stdlib.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,99 @@ ++#ifndef __KORBIT_STDLIB_H__ ++#define __KORBIT_STDLIB_H__ ++ ++#include <linux/kernel.h> ++#include <linux/malloc.h> ++#include <linux/types.h> ++#include <asm/string.h> ++ ++#define strtol(nptr,endptr,base) simple_strtol(nptr,endptr,base) ++ ++#if 0 ++#define malloc(size) kmalloc(size, GFP_KERNEL) ++#define free(ptr) kfree(ptr) ++#endif ++ ++static inline void *malloc(size_t size) ++{ ++ void *ptr = NULL; ++ ++ if (size == 0) ++ size = 4; ++ ++ ptr = kmalloc(size + sizeof(size), GFP_KERNEL); ++ ++ if (ptr) ++ { ++ *((size_t *)ptr) = size; ++ ptr = (size_t *)ptr + 1; ++ } ++ ++ return ptr; ++} ++ ++static inline void free(void *ptr) ++{ ++ if (ptr) ++ kfree((size_t *)ptr - 1); ++} ++ ++#define alloca(size) malloc(size) ++ ++/* freeca(ptr) - free a mem allocation if ptr points to one, otherwise do ++ * nothing. ++ */ ++static inline void freeca(void *ptr) ++{ ++ if (ptr != NULL) { /* Don't free it if it's already free */ ++ free(ptr); ++ } ++} ++ ++static inline void *calloc(size_t nmemb, size_t size) ++{ ++ void *ptr = malloc(nmemb*size); ++ if (ptr) ++ memset(ptr,0,nmemb*size); ++ return ptr; ++} ++ ++static inline void *realloc(void *ptr, size_t size) ++{ ++ void *newptr = NULL; ++ ++ if (size != 0) ++ newptr = malloc(size); ++ ++ if (ptr && newptr) /* Copy old contents */ ++ { ++ size_t *p1 = (size_t *)ptr - 1; ++ size_t *p2 = (size_t *)newptr - 1; ++ size_t n = *p1 < *p2 ? *p1 : *p2; ++ memcpy(newptr, ptr, n); ++ } ++ ++ if (ptr) ++ free(ptr); ++ ++ return newptr; ++} ++ ++/* Returned by `div'. */ ++typedef struct ++{ ++ int quot; /* Quotient. */ ++ int rem; /* Remainder. */ ++} div_t; ++ ++static inline div_t div(int number, int denom) ++{ ++ div_t result; ++ result.quot = number/denom; ++ result.rem = number-(number*result.quot); ++ return result; ++} ++ ++#define atexit(fn) -1 ++#define getenv(name) 0 ++ ++#endif /* __KORBIT_STDLIB_H__ */ +diff -urN linux-2.4.1/net/korbit/include/string.h linux-2.4.1-korbit/net/korbit/include/string.h +--- linux-2.4.1/net/korbit/include/string.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/string.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,11 @@ ++#ifndef __KORBIT_STRING_H__ ++#define __KORBIT_STRING_H__ ++ ++#include <linux/types.h> ++#include <asm/string.h> ++ ++#include <glib.h> ++ ++#define strerror(errno) g_strerror(errno) ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Entries linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries +--- linux-2.4.1/net/korbit/include/sys/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Entries Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,10 @@ ++/ioctl.h/1.1.1.1/Thu Feb 1 09:46:55 2001// ++/poll.h/1.25/Thu Feb 1 09:46:55 2001// ++/socket.h/1.20/Thu Feb 1 09:46:55 2001// ++/stat.h/1.1.1.1/Thu Feb 1 09:46:55 2001// ++/time.h/1.1.1.1/Thu Feb 1 09:46:55 2001// ++/types.h/1.1.1.1/Thu Feb 1 09:46:56 2001// ++/uio.h/1.1.1.1/Thu Feb 1 09:46:56 2001// ++/un.h/1.1.1.1/Thu Feb 1 09:46:56 2001// ++/wait.h/1.1.1.1/Thu Feb 1 09:46:56 2001// ++D +diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Repository linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository +--- linux-2.4.1/net/korbit/include/sys/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Repository Thu Feb 1 11:46:55 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/include/sys +diff -urN linux-2.4.1/net/korbit/include/sys/CVS/Root linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root +--- linux-2.4.1/net/korbit/include/sys/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/CVS/Root Thu Feb 1 11:46:55 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/include/sys/ioctl.h linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h +--- linux-2.4.1/net/korbit/include/sys/ioctl.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/ioctl.h Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_SYS_IOCTL_H__ ++#define __KORBIT_SYS_IOCTL_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/poll.h linux-2.4.1-korbit/net/korbit/include/sys/poll.h +--- linux-2.4.1/net/korbit/include/sys/poll.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/poll.h Fri Feb 2 01:22:10 2001 +@@ -0,0 +1,112 @@ ++#ifndef __KORBIT_SYS_POLL_H__ ++#define __KORBIT_SYS_POLL_H__ ++ ++#include <asm/poll.h> ++#include <asm/param.h> ++#include <linux/net.h> ++#include <linux/tcp.h> ++#include <linux/socket.h> ++#include <net/tcp.h> ++#include <net/sock.h> ++#include <linux/skbuff.h> ++#include <linux/sched.h> ++#include "stdlib.h" ++#include "sys/socket.h" ++ ++/* Poll the file descriptors described by the NFDS structures starting at ++ * FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for ++ * an event to occur; if TIMEOUT is -1, block until an event occurs. ++ * Returns the number of file descriptors with events, zero if timed ++ * out, or -1 for errors. ++ */ ++ ++/* This implementation of poll assumes that we are sitting on the wait ++ * queues for all of the file descriptors already. Therefore if we are about ++ * to block, all we have to do is perform the schedule call which will ++ * automatically cause us to "block". ++ */ ++static int poll_CheckFDs(struct pollfd *fds, unsigned long int nfds) ++{ ++ int NumReady = 0, i; ++ ++ // Loop over the file descriptors seeing if there is already work to be ++ // done... ++ for (i = 0; i < nfds; i++) { ++ struct socket *sock = fd2sock(fds[i].fd); ++ fds[i].revents = 0; ++ ++ // Check to see if stuff is available to read ++ if (sock) { ++ // It's a socket baby ++ fds[i].revents = tcp_poll(0, sock, 0); ++ ++ // Apparently tcp_poll doesn't look at the CLOSE_WAIT value, ++ // and we have a lot of sockets that end up in this state. ++ // This is a hack to shortcircuit some read failures from ++ // later. This breaks "poll semantics" strictly speaking, but ++ // it's basically the "right thing to do" (tm). ++ if (sock->sk->state == TCP_CLOSE_WAIT) ++ fds[i].revents = POLLHUP; ++ fds[i].revents &= fds[i].events | POLLERR | POLLHUP; ++ } else { ++ // It's a file ++ //struct file *f = fd2file(fd); ++// printk("POLL NOT IMPLEMENTED FOR FILES YET\n"); ++ BUG(); ++ } ++ ++ if (fds[i].revents) { ++ NumReady++; ++// printk("FD #%d: Event = 0x%X\n", i, fds[i].revents); ++ } ++ ++ } /* for */ ++ ++ return NumReady; ++} /* End poll_CheckFDs(). */ ++ ++ ++static int poll(struct pollfd *fds, unsigned long int nfds, int timeout) { ++ wait_queue_t *WaitQueues = 0; ++ int NumReady = poll_CheckFDs(fds, nfds); ++ int i; ++ ++ if (NumReady || timeout == 0) ++ return NumReady; ++ ++// printk("Starting to Poll... %d fds...\n", nfds); ++ WaitQueues = (wait_queue_t*)malloc(nfds*sizeof(wait_queue_t)); ++ if (WaitQueues == 0) return 0; // Crap, nomem... ++ ++ for (i = 0; i < nfds; i++) { ++ struct socket *sock = fd2sock(fds[i].fd); ++ init_waitqueue_entry(WaitQueues+i, current); ++ ++ if (sock) ++ add_wait_queue_exclusive(sock->sk->sleep, WaitQueues+i); ++// else ++// printk("I don't know how to wait on fd #%d = 0x%X\n", i, fds[i].fd); ++ } ++ ++ // Wait for us to get notified by one of the socket wait queue notifiers! ++ do { ++ // Change our task state so that we are not immediately rescheduled. ++ // This lets the scheduler know that we are waiting for something to happen ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ } while (!(NumReady = poll_CheckFDs(fds, nfds))); ++ ++ set_current_state(TASK_RUNNING); ++ ++ for (i = 0; i < nfds; i++) { ++ struct socket *sock = fd2sock(fds[i].fd); ++ if (sock) ++ remove_wait_queue(sock->sk->sleep, WaitQueues+i); ++ } ++ ++ free(WaitQueues); ++// printk("Returning %d\n", NumReady); ++ return NumReady; ++} ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/socket.h linux-2.4.1-korbit/net/korbit/include/sys/socket.h +--- linux-2.4.1/net/korbit/include/sys/socket.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/socket.h Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,126 @@ ++#ifndef __KORBIT_SYS_SOCKET_H__ ++#define __KORBIT_SYS_SOCKET_H__ ++typedef unsigned int socklen_t; ++ ++#include <linux/socket.h> ++#include <linux/wait.h> ++#include <asm/semaphore.h> ++#include <net/sock.h> ++ ++/* These functions are declared in net/socket.c */ ++asmlinkage long sys_socket(int family, int type, int protocol); ++struct socket *sockfd_lookup(int fd, int *err); ++ ++ ++static inline int sock2fd(struct socket *s) ++{ ++ return (-(int)s) | 1; ++} ++ ++static inline struct socket *fd2sock(int sockfd) ++{ ++ if ((sockfd & 1) == 0) /* can't convert a file! */ ++ return NULL; ++ ++ return (struct socket *)(-(sockfd & ~1)); ++} ++ ++ ++static inline int socket(int domain, int type, int protocol) { ++ struct socket *sock; ++ int retval = sock_create(domain, type, protocol, &sock); ++ ++ if (retval < 0) return (int)NULL; ++ return sock2fd(sock); ++} ++ ++ ++static inline int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) ++{ ++ struct socket *sock = fd2sock(sockfd); ++ ++ if (sock == NULL) ++ return -1; ++ if (!sock->ops->bind(sock, my_addr, addrlen)) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} ++ ++ ++static inline int connect(int sockfd, const struct sockaddr *serv_addr, ++ socklen_t addrlen) ++{ ++ struct socket *sock = fd2sock(sockfd); ++ int flags = 0; /* TODO : what is flags supposed to be? */ ++ ++ if (sock == NULL) ++ return -1; ++ ++ if (sock->ops->connect(sock, (struct sockaddr *)serv_addr, addrlen, flags) == 0) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} ++ ++ ++static inline int listen(int sockfd, int backlog) ++{ ++ struct socket *sock = fd2sock(sockfd); ++ ++ if (sock == NULL) ++ return -1; ++ ++ if (sock->ops->listen(sock, backlog) == 0) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} ++ ++ ++static inline int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) ++{ ++ struct socket *sock = fd2sock(sockfd); ++ struct socket *newsock; ++ struct sockaddr_in *newaddr = (struct sockaddr_in *)addr; /* check? */ ++ int flags = 0; /* Should be ok */ ++ ++ if (sock == 0) ++ return -1; ++ ++ newsock = sock_alloc(); ++ if (newsock == 0) ++ return -1; ++ ++ newsock->type = sock->type; ++ newsock->ops = sock->ops; ++ if (sock->ops->accept(sock, newsock, flags) < 0) ++ { ++ sock_release(newsock); ++ return -1; /* should normally also set errno */ ++ } ++ ++ newaddr->sin_family = AF_INET; ++ newaddr->sin_port = newsock->sk->dport; ++ newaddr->sin_addr.s_addr = newsock->sk->daddr; ++ ++ *addrlen = sizeof(newaddr); ++ ++ return sock2fd(newsock); ++} ++ ++ ++static inline int shutdown(int sockfd, int how) ++{ ++ struct socket *sock = fd2sock(sockfd); ++ ++ if (sock == NULL) ++ return -1; ++ ++ if (sock->ops->shutdown(sock, how) == 0) ++ return 0; ++ else ++ return -1; /* should normally also set errno */ ++} ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/stat.h linux-2.4.1-korbit/net/korbit/include/sys/stat.h +--- linux-2.4.1/net/korbit/include/sys/stat.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/stat.h Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_SYS_STAT_H__ ++#define __KORBIT_SYS_STAT_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/time.h linux-2.4.1-korbit/net/korbit/include/sys/time.h +--- linux-2.4.1/net/korbit/include/sys/time.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/time.h Thu Feb 1 11:46:55 2001 +@@ -0,0 +1,6 @@ ++#ifndef __KORBIT_TIME_H__ ++#define __KORBIT_TIME_H__ ++ ++#include <linux/time.h> ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/types.h linux-2.4.1-korbit/net/korbit/include/sys/types.h +--- linux-2.4.1/net/korbit/include/sys/types.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/types.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,4 @@ ++#ifndef __KORBIT_SYS_TYPES_H__ ++#define __KORBIT_SYS_TYPES_H__ ++#include <linux/types.h> ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/uio.h linux-2.4.1-korbit/net/korbit/include/sys/uio.h +--- linux-2.4.1/net/korbit/include/sys/uio.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/uio.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,4 @@ ++#ifndef __KORBIT_SYS_UIO_H__ ++#define __KORBIT_SYS_UIO_H__ ++#include <linux/uio.h> ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/un.h linux-2.4.1-korbit/net/korbit/include/sys/un.h +--- linux-2.4.1/net/korbit/include/sys/un.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/un.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,5 @@ ++#ifndef __KORBIT_SYS_UN_H__ ++#define __KORBIT_SYS_UN_H__ ++#include <linux/socket.h> ++#include <linux/un.h> ++#endif +diff -urN linux-2.4.1/net/korbit/include/sys/wait.h linux-2.4.1-korbit/net/korbit/include/sys/wait.h +--- linux-2.4.1/net/korbit/include/sys/wait.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/sys/wait.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,3 @@ ++#ifndef __KORBIT_SYS_WAIT_H__ ++#define __KORBIT_SYS_WAIT_H__ ++#endif +diff -urN linux-2.4.1/net/korbit/include/syslog.h linux-2.4.1-korbit/net/korbit/include/syslog.h +--- linux-2.4.1/net/korbit/include/syslog.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/syslog.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,7 @@ ++#ifndef __KORBIT_SYSLOG_H__ ++#define __KORBIT_SYSLOG_H__ ++ ++#define LOG_NOTICE 5 /* normal but significant condition */ ++#define LOG_INFO 6 /* informational */ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/time.h linux-2.4.1-korbit/net/korbit/include/time.h +--- linux-2.4.1/net/korbit/include/time.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/time.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,4 @@ ++#ifndef __KORBIT_TIME_H__ ++#define __KORBIT_TIME_H__ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/unistd.h linux-2.4.1-korbit/net/korbit/include/unistd.h +--- linux-2.4.1/net/korbit/include/unistd.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/unistd.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,19 @@ ++#ifndef __KORBIT_UNISTD_H__ ++#define __KORBIT_UNISTD_H__ ++ ++#include <linux/types.h> ++#include <linux/utsname.h> ++#include <asm/string.h> ++#include <asm/semaphore.h> ++/* extern char *getcwd(char * buf, size_t size); */ ++ ++static inline int gethostname(char *name, size_t len) { ++ down_read(&uts_sem); ++ strncpy(name, system_utsname.nodename, len); ++ up_read(&uts_sem); ++printk("gethostname() = %s\n", name); ++ return 0; ++} ++ ++ ++#endif +diff -urN linux-2.4.1/net/korbit/include/utime.h linux-2.4.1-korbit/net/korbit/include/utime.h +--- linux-2.4.1/net/korbit/include/utime.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/include/utime.h Thu Feb 1 11:46:54 2001 +@@ -0,0 +1,4 @@ ++#ifndef __KORBIT_UTIME_H__ ++#define __KORBIT_UTIME_H__ ++#include <linux/utime.h> ++#endif +diff -urN linux-2.4.1/net/korbit/kglib/CVS/Entries linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries +--- linux-2.4.1/net/korbit/kglib/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Entries Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,15 @@ ++/Makefile/1.4/Thu Feb 1 09:46:56 2001// ++/garray.c/1.3/Thu Feb 1 09:46:56 2001// ++/ghash.c/1.2/Thu Feb 1 09:46:56 2001// ++/glib.h/1.3/Thu Feb 1 09:46:56 2001// ++/glibconfig.h/1.2/Thu Feb 1 09:46:56 2001// ++/glist.c/1.1.1.1/Thu Feb 1 09:46:57 2001// ++/gmem.c/1.2/Thu Feb 1 09:46:57 2001// ++/gprimes.c/1.1.1.1/Thu Feb 1 09:46:57 2001// ++/gslist.c/1.1.1.1/Thu Feb 1 09:46:57 2001// ++/gstrfuncs.c/1.2/Thu Feb 1 09:46:57 2001// ++/gstring.c/1.1.1.1/Thu Feb 1 09:46:57 2001// ++/gtree.c/1.1.1.1/Thu Feb 1 09:46:57 2001// ++/gutils.c/1.2/Thu Feb 1 09:46:57 2001// ++/korbit_errno.c/1.1/Thu Feb 1 09:46:57 2001// ++D +diff -urN linux-2.4.1/net/korbit/kglib/CVS/Repository linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository +--- linux-2.4.1/net/korbit/kglib/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Repository Thu Feb 1 11:46:56 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/kglib +diff -urN linux-2.4.1/net/korbit/kglib/CVS/Root linux-2.4.1-korbit/net/korbit/kglib/CVS/Root +--- linux-2.4.1/net/korbit/kglib/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/CVS/Root Thu Feb 1 11:46:56 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/kglib/Makefile linux-2.4.1-korbit/net/korbit/kglib/Makefile +--- linux-2.4.1/net/korbit/kglib/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/Makefile Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,18 @@ ++# ++# Makefile for KORBit/kglib ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := kglib.o ++ ++#obj-m := $(O_TARGET) ++obj-y := garray.o glist.o gprimes.o gstrfuncs.o gtree.o \ ++ ghash.o gmem.o gslist.o gstring.o gutils.o korbit_errno.o ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -DHAVE_UNISTD_H -I. -I.. -I../include -nostdinc ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/kglib/garray.c linux-2.4.1-korbit/net/korbit/kglib/garray.c +--- linux-2.4.1/net/korbit/kglib/garray.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/garray.c Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,431 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include <string.h> ++#include "glib.h" ++ ++ ++#define MIN_ARRAY_SIZE 16 ++ ++ ++typedef struct _GRealArray GRealArray; ++ ++struct _GRealArray ++{ ++ guint8 *data; ++ guint len; ++ guint alloc; ++ guint elt_size; ++ guint zero_terminated : 1; ++ guint clear : 1; ++}; ++ ++ ++static gint g_nearest_pow (gint num); ++static void g_array_maybe_expand (GRealArray *array, ++ gint len); ++ ++static GMemChunk *array_mem_chunk = NULL; ++G_LOCK_DEFINE_STATIC (array_mem_chunk); ++ ++GArray* ++g_array_new (gboolean zero_terminated, ++ gboolean clear, ++ guint elt_size) ++{ ++ GRealArray *array; ++ ++ G_LOCK (array_mem_chunk); ++ if (!array_mem_chunk) ++ array_mem_chunk = g_mem_chunk_new ("array mem chunk", ++ sizeof (GRealArray), ++ 1024, G_ALLOC_AND_FREE); ++ ++ array = g_chunk_new (GRealArray, array_mem_chunk); ++ G_UNLOCK (array_mem_chunk); ++ ++ array->data = NULL; ++ array->len = 0; ++ array->alloc = 0; ++ array->zero_terminated = (zero_terminated ? 1 : 0); ++ array->clear = (clear ? 1 : 0); ++ array->elt_size = elt_size; ++ ++ return (GArray*) array; ++} ++ ++void ++g_array_free (GArray *array, ++ gboolean free_segment) ++{ ++ if (free_segment) ++ g_free (array->data); ++ ++ G_LOCK (array_mem_chunk); ++ g_mem_chunk_free (array_mem_chunk, array); ++ G_UNLOCK (array_mem_chunk); ++} ++ ++GArray* ++g_array_append_vals (GArray *farray, ++ gconstpointer data, ++ guint len) ++{ ++ GRealArray *array = (GRealArray*) farray; ++ ++ g_array_maybe_expand (array, len); ++ ++ memcpy (array->data + array->elt_size * array->len, data, array->elt_size * len); ++ ++ array->len += len; ++ ++ return farray; ++} ++ ++GArray* ++g_array_prepend_vals (GArray *farray, ++ gconstpointer data, ++ guint len) ++{ ++ GRealArray *array = (GRealArray*) farray; ++ ++ g_array_maybe_expand (array, len); ++ ++ g_memmove (array->data + array->elt_size * len, array->data, array->elt_size * array->len); ++ ++ memcpy (array->data, data, len * array->elt_size); ++ ++ array->len += len; ++ ++ return farray; ++} ++ ++GArray* ++g_array_insert_vals (GArray *farray, ++ guint index, ++ gconstpointer data, ++ guint len) ++{ ++ GRealArray *array = (GRealArray*) farray; ++ ++ g_array_maybe_expand (array, len); ++ ++ g_memmove (array->data + array->elt_size * (len + index), ++ array->data + array->elt_size * index, ++ array->elt_size * (array->len - index)); ++ ++ memcpy (array->data + array->elt_size * index, data, len * array->elt_size); ++ ++ array->len += len; ++ ++ return farray; ++} ++ ++GArray* ++g_array_set_size (GArray *farray, ++ guint length) ++{ ++ GRealArray *array = (GRealArray*) farray; ++ ++ if (array->len < length) ++ g_array_maybe_expand (array, length - array->len); ++ ++ array->len = length; ++ ++ return farray; ++} ++ ++GArray* ++g_array_remove_index (GArray* farray, ++ guint index) ++{ ++ GRealArray* array = (GRealArray*) farray; ++ ++ g_return_val_if_fail (array, NULL); ++ ++ g_return_val_if_fail (index < array->len, NULL); ++ ++ if (index != array->len - 1) ++ g_memmove (array->data + array->elt_size * index, ++ array->data + array->elt_size * (index + 1), ++ array->elt_size * (array->len - index - 1)); ++ ++ if (array->zero_terminated) ++ memset (array->data + array->elt_size * (array->len - 1), 0, ++ array->elt_size); ++ ++ array->len -= 1; ++ ++ return farray; ++} ++ ++GArray* ++g_array_remove_index_fast (GArray* farray, ++ guint index) ++{ ++ GRealArray* array = (GRealArray*) farray; ++ ++ g_return_val_if_fail (array, NULL); ++ ++ g_return_val_if_fail (index < array->len, NULL); ++ ++ if (index != array->len - 1) ++ g_memmove (array->data + array->elt_size * index, ++ array->data + array->elt_size * (array->len - 1), ++ array->elt_size); ++ ++ if (array->zero_terminated) ++ memset (array->data + array->elt_size * (array->len - 1), 0, ++ array->elt_size); ++ ++ array->len -= 1; ++ ++ return farray; ++} ++ ++static gint ++g_nearest_pow (gint num) ++{ ++ gint n = 1; ++ ++ while (n < num) ++ n <<= 1; ++ ++ return n; ++} ++ ++static void ++g_array_maybe_expand (GRealArray *array, ++ gint len) ++{ ++ guint want_alloc = (array->len + len + array->zero_terminated) * array->elt_size; ++ ++ if (want_alloc > array->alloc) ++ { ++ guint old_alloc = array->alloc; ++ ++ array->alloc = g_nearest_pow (want_alloc); ++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE); ++ ++ array->data = g_realloc (array->data, array->alloc); ++ ++ if (array->clear || array->zero_terminated) ++ memset (array->data + old_alloc, 0, array->alloc - old_alloc); ++ } ++} ++ ++/* Pointer Array ++ */ ++ ++typedef struct _GRealPtrArray GRealPtrArray; ++ ++struct _GRealPtrArray ++{ ++ gpointer *pdata; ++ guint len; ++ guint alloc; ++}; ++ ++static void g_ptr_array_maybe_expand (GRealPtrArray *array, ++ gint len); ++ ++static GMemChunk *ptr_array_mem_chunk = NULL; ++G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk); ++ ++ ++GPtrArray* ++g_ptr_array_new (void) ++{ ++ GRealPtrArray *array; ++ ++ G_LOCK (ptr_array_mem_chunk); ++ if (!ptr_array_mem_chunk) ++ ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk", ++ sizeof (GRealPtrArray), ++ 1024, G_ALLOC_AND_FREE); ++ ++ array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk); ++ G_UNLOCK (ptr_array_mem_chunk); ++ ++ array->pdata = NULL; ++ array->len = 0; ++ array->alloc = 0; ++ ++ return (GPtrArray*) array; ++} ++ ++void ++g_ptr_array_free (GPtrArray *array, ++ gboolean free_segment) ++{ ++ g_return_if_fail (array); ++ ++ if (free_segment) ++ g_free (array->pdata); ++ ++ G_LOCK (ptr_array_mem_chunk); ++ g_mem_chunk_free (ptr_array_mem_chunk, array); ++ G_UNLOCK (ptr_array_mem_chunk); ++} ++ ++static void ++g_ptr_array_maybe_expand (GRealPtrArray *array, ++ gint len) ++{ ++ guint old_alloc; ++ ++ if ((array->len + len) > array->alloc) ++ { ++ old_alloc = array->alloc; ++ ++ array->alloc = g_nearest_pow (array->len + len); ++ array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE); ++ if (array->pdata) ++ array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc); ++ else ++ array->pdata = g_new0 (gpointer, array->alloc); ++ ++ memset (array->pdata + old_alloc, 0, ++ sizeof (gpointer) * (array->alloc - old_alloc)); ++ } ++} ++ ++void ++g_ptr_array_set_size (GPtrArray *farray, ++ gint length) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ ++ g_return_if_fail (array); ++ ++ if (length > array->len) ++ g_ptr_array_maybe_expand (array, (length - array->len)); ++ ++ array->len = length; ++} ++ ++gpointer ++g_ptr_array_remove_index (GPtrArray* farray, ++ guint index) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ gpointer result; ++ ++ g_return_val_if_fail (array, NULL); ++ ++ g_return_val_if_fail (index < array->len, NULL); ++ ++ result = array->pdata[index]; ++ ++ if (index != array->len - 1) ++ g_memmove (array->pdata + index, array->pdata + index + 1, ++ sizeof (gpointer) * (array->len - index - 1)); ++ ++ array->pdata[array->len - 1] = NULL; ++ ++ array->len -= 1; ++ ++ return result; ++} ++ ++gpointer ++g_ptr_array_remove_index_fast (GPtrArray* farray, ++ guint index) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ gpointer result; ++ ++ g_return_val_if_fail (array, NULL); ++ ++ g_return_val_if_fail (index < array->len, NULL); ++ ++ result = array->pdata[index]; ++ ++ if (index != array->len - 1) ++ array->pdata[index] = array->pdata[array->len - 1]; ++ ++ array->pdata[array->len - 1] = NULL; ++ ++ array->len -= 1; ++ ++ return result; ++} ++ ++gboolean ++g_ptr_array_remove (GPtrArray* farray, ++ gpointer data) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ int i; ++ ++ g_return_val_if_fail (array, FALSE); ++ ++ for (i = 0; i < array->len; i += 1) ++ { ++ if (array->pdata[i] == data) ++ { ++ g_ptr_array_remove_index (farray, i); ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++gboolean ++g_ptr_array_remove_fast (GPtrArray* farray, ++ gpointer data) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ int i; ++ ++ g_return_val_if_fail (array, FALSE); ++ ++ for (i = 0; i < array->len; i += 1) ++ { ++ if (array->pdata[i] == data) ++ { ++ g_ptr_array_remove_index_fast (farray, i); ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++void ++g_ptr_array_add (GPtrArray* farray, ++ gpointer data) ++{ ++ GRealPtrArray* array = (GRealPtrArray*) farray; ++ ++ g_return_if_fail (array); ++ ++ g_ptr_array_maybe_expand (array, 1); ++ ++ array->pdata[array->len++] = data; ++} ++ +diff -urN linux-2.4.1/net/korbit/kglib/ghash.c linux-2.4.1-korbit/net/korbit/kglib/ghash.c +--- linux-2.4.1/net/korbit/kglib/ghash.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/ghash.c Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,404 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include "glib.h" ++ ++ ++#define HASH_TABLE_MIN_SIZE 11 ++#define HASH_TABLE_MAX_SIZE 13845163 ++ ++ ++typedef struct _GHashNode GHashNode; ++ ++struct _GHashNode ++{ ++ gpointer key; ++ gpointer value; ++ GHashNode *next; ++}; ++ ++struct _GHashTable ++{ ++ gint size; ++ gint nnodes; ++ guint frozen; ++ GHashNode **nodes; ++ GHashFunc hash_func; ++ GCompareFunc key_compare_func; ++}; ++ ++ ++static void g_hash_table_resize (GHashTable *hash_table); ++static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table, ++ gconstpointer key); ++static GHashNode* g_hash_node_new (gpointer key, ++ gpointer value); ++static void g_hash_node_destroy (GHashNode *hash_node); ++static void g_hash_nodes_destroy (GHashNode *hash_node); ++ ++ ++G_LOCK_DEFINE_STATIC (g_hash_global); ++ ++static GMemChunk *node_mem_chunk = NULL; ++static GHashNode *node_free_list = NULL; ++ ++ ++GHashTable* ++g_hash_table_new (GHashFunc hash_func, ++ GCompareFunc key_compare_func) ++{ ++ GHashTable *hash_table; ++ guint i; ++ ++ hash_table = g_new (GHashTable, 1); ++ hash_table->size = HASH_TABLE_MIN_SIZE; ++ hash_table->nnodes = 0; ++ hash_table->frozen = FALSE; ++ hash_table->hash_func = hash_func ? hash_func : g_direct_hash; ++ hash_table->key_compare_func = key_compare_func; ++ hash_table->nodes = g_new (GHashNode*, hash_table->size); ++ ++ for (i = 0; i < hash_table->size; i++) ++ hash_table->nodes[i] = NULL; ++ ++ return hash_table; ++} ++ ++void ++g_hash_table_destroy (GHashTable *hash_table) ++{ ++ guint i; ++ ++ g_return_if_fail (hash_table != NULL); ++ ++ for (i = 0; i < hash_table->size; i++) ++ g_hash_nodes_destroy (hash_table->nodes[i]); ++ ++ g_free (hash_table->nodes); ++ g_free (hash_table); ++} ++ ++static inline GHashNode** ++g_hash_table_lookup_node (GHashTable *hash_table, ++ gconstpointer key) ++{ ++ GHashNode **node; ++ ++ node = &hash_table->nodes ++ [(* hash_table->hash_func) (key) % hash_table->size]; ++ ++ /* Hash table lookup needs to be fast. ++ * We therefore remove the extra conditional of testing ++ * whether to call the key_compare_func or not from ++ * the inner loop. ++ */ ++ if (hash_table->key_compare_func) ++ while (*node && !(*hash_table->key_compare_func) ((*node)->key, key)) ++ node = &(*node)->next; ++ else ++ while (*node && (*node)->key != key) ++ node = &(*node)->next; ++ ++ return node; ++} ++ ++gpointer ++g_hash_table_lookup (GHashTable *hash_table, ++ gconstpointer key) ++{ ++ GHashNode *node; ++ ++ g_return_val_if_fail (hash_table != NULL, NULL); ++ ++ node = *g_hash_table_lookup_node (hash_table, key); ++ ++ return node ? node->value : NULL; ++} ++ ++void ++g_hash_table_insert (GHashTable *hash_table, ++ gpointer key, ++ gpointer value) ++{ ++ GHashNode **node; ++ ++ g_return_if_fail (hash_table != NULL); ++ ++ node = g_hash_table_lookup_node (hash_table, key); ++ ++ if (*node) ++ { ++ /* do not reset node->key in this place, keeping ++ * the old key might be intended. ++ * a g_hash_table_remove/g_hash_table_insert pair ++ * can be used otherwise. ++ * ++ * node->key = key; */ ++ (*node)->value = value; ++ } ++ else ++ { ++ *node = g_hash_node_new (key, value); ++ hash_table->nnodes++; ++ if (!hash_table->frozen) ++ g_hash_table_resize (hash_table); ++ } ++} ++ ++void ++g_hash_table_remove (GHashTable *hash_table, ++ gconstpointer key) ++{ ++ GHashNode **node, *dest; ++ ++ g_return_if_fail (hash_table != NULL); ++ ++ node = g_hash_table_lookup_node (hash_table, key); ++ ++ if (*node) ++ { ++ dest = *node; ++ (*node) = dest->next; ++ g_hash_node_destroy (dest); ++ hash_table->nnodes--; ++ ++ if (!hash_table->frozen) ++ g_hash_table_resize (hash_table); ++ } ++} ++ ++gboolean ++g_hash_table_lookup_extended (GHashTable *hash_table, ++ gconstpointer lookup_key, ++ gpointer *orig_key, ++ gpointer *value) ++{ ++ GHashNode *node; ++ ++ g_return_val_if_fail (hash_table != NULL, FALSE); ++ ++ node = *g_hash_table_lookup_node (hash_table, lookup_key); ++ ++ if (node) ++ { ++ if (orig_key) ++ *orig_key = node->key; ++ if (value) ++ *value = node->value; ++ return TRUE; ++ } ++ else ++ return FALSE; ++} ++ ++void ++g_hash_table_freeze (GHashTable *hash_table) ++{ ++ g_return_if_fail (hash_table != NULL); ++ ++ hash_table->frozen++; ++} ++ ++void ++g_hash_table_thaw (GHashTable *hash_table) ++{ ++ g_return_if_fail (hash_table != NULL); ++ ++ if (hash_table->frozen) ++ if (!(--hash_table->frozen)) ++ g_hash_table_resize (hash_table); ++} ++ ++guint ++g_hash_table_foreach_remove (GHashTable *hash_table, ++ GHRFunc func, ++ gpointer user_data) ++{ ++ GHashNode *node, *prev; ++ guint i; ++ guint deleted = 0; ++ ++ g_return_val_if_fail (hash_table != NULL, 0); ++ g_return_val_if_fail (func != NULL, 0); ++ ++ for (i = 0; i < hash_table->size; i++) ++ { ++ restart: ++ ++ prev = NULL; ++ ++ for (node = hash_table->nodes[i]; node; prev = node, node = node->next) ++ { ++ if ((* func) (node->key, node->value, user_data)) ++ { ++ deleted += 1; ++ ++ hash_table->nnodes -= 1; ++ ++ if (prev) ++ { ++ prev->next = node->next; ++ g_hash_node_destroy (node); ++ node = prev; ++ } ++ else ++ { ++ hash_table->nodes[i] = node->next; ++ g_hash_node_destroy (node); ++ goto restart; ++ } ++ } ++ } ++ } ++ ++ if (!hash_table->frozen) ++ g_hash_table_resize (hash_table); ++ ++ return deleted; ++} ++ ++void ++g_hash_table_foreach (GHashTable *hash_table, ++ GHFunc func, ++ gpointer user_data) ++{ ++ GHashNode *node; ++ gint i; ++ ++ g_return_if_fail (hash_table != NULL); ++ g_return_if_fail (func != NULL); ++ ++ for (i = 0; i < hash_table->size; i++) ++ for (node = hash_table->nodes[i]; node; node = node->next) ++ (* func) (node->key, node->value, user_data); ++} ++ ++/* Returns the number of elements contained in the hash table. */ ++guint ++g_hash_table_size (GHashTable *hash_table) ++{ ++ g_return_val_if_fail (hash_table != NULL, 0); ++ ++ return hash_table->nnodes; ++} ++ ++static void ++g_hash_table_resize (GHashTable *hash_table) ++{ ++ GHashNode **new_nodes; ++ GHashNode *node; ++ GHashNode *next; ++#ifdef __KORBIT__ ++ guint nodes_per_list; ++#else ++ gfloat nodes_per_list; ++#endif ++ guint hash_val; ++ gint new_size; ++ gint i; ++ ++ nodes_per_list = (hash_table->nnodes * 10) / hash_table->size; ++ ++ if ((nodes_per_list > 3 || hash_table->size <= HASH_TABLE_MIN_SIZE) && ++ (nodes_per_list < 30 || hash_table->size >= HASH_TABLE_MAX_SIZE)) ++ return; ++ ++ new_size = CLAMP(g_spaced_primes_closest (hash_table->nnodes), ++ HASH_TABLE_MIN_SIZE, ++ HASH_TABLE_MAX_SIZE); ++ new_nodes = g_new0 (GHashNode*, new_size); ++ ++ for (i = 0; i < hash_table->size; i++) ++ for (node = hash_table->nodes[i]; node; node = next) ++ { ++ next = node->next; ++ ++ hash_val = (* hash_table->hash_func) (node->key) % new_size; ++ ++ node->next = new_nodes[hash_val]; ++ new_nodes[hash_val] = node; ++ } ++ ++ g_free (hash_table->nodes); ++ hash_table->nodes = new_nodes; ++ hash_table->size = new_size; ++} ++ ++static GHashNode* ++g_hash_node_new (gpointer key, ++ gpointer value) ++{ ++ GHashNode *hash_node; ++ ++ G_LOCK (g_hash_global); ++ if (node_free_list) ++ { ++ hash_node = node_free_list; ++ node_free_list = node_free_list->next; ++ } ++ else ++ { ++ if (!node_mem_chunk) ++ node_mem_chunk = g_mem_chunk_new ("hash node mem chunk", ++ sizeof (GHashNode), ++ 1024, G_ALLOC_ONLY); ++ ++ hash_node = g_chunk_new (GHashNode, node_mem_chunk); ++ } ++ G_UNLOCK (g_hash_global); ++ ++ hash_node->key = key; ++ hash_node->value = value; ++ hash_node->next = NULL; ++ ++ return hash_node; ++} ++ ++static void ++g_hash_node_destroy (GHashNode *hash_node) ++{ ++ G_LOCK (g_hash_global); ++ hash_node->next = node_free_list; ++ node_free_list = hash_node; ++ G_UNLOCK (g_hash_global); ++} ++ ++static void ++g_hash_nodes_destroy (GHashNode *hash_node) ++{ ++ if (hash_node) ++ { ++ GHashNode *node = hash_node; ++ ++ while (node->next) ++ node = node->next; ++ ++ G_LOCK (g_hash_global); ++ node->next = node_free_list; ++ node_free_list = hash_node; ++ G_UNLOCK (g_hash_global); ++ } ++} +diff -urN linux-2.4.1/net/korbit/kglib/glib.h linux-2.4.1-korbit/net/korbit/kglib/glib.h +--- linux-2.4.1/net/korbit/kglib/glib.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/glib.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,1671 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++#ifndef __G_LIB_H__ ++#define __G_LIB_H__ ++ ++#ifdef __KORBIT__ ++#define G_DISABLE_ASSERT 1 ++#include <stdio.h> ++#endif ++ ++#include "config.h" ++ ++/* system specific config file glibconfig.h provides definitions for ++ * the extrema of many of the standard types. These are: ++ * ++ * G_MINSHORT, G_MAXSHORT ++ * G_MININT, G_MAXINT ++ * G_MINLONG, G_MAXLONG ++ * G_MINFLOAT, G_MAXFLOAT ++ * G_MINDOUBLE, G_MAXDOUBLE ++ * ++ * It also provides the following typedefs: ++ * ++ * gint8, guint8 ++ * gint16, guint16 ++ * gint32, guint32 ++ * gint64, guint64 ++ * ++ * It defines the G_BYTE_ORDER symbol to one of G_*_ENDIAN (see later in ++ * this file). ++ * ++ * And it provides a way to store and retrieve a `gint' in/from a `gpointer'. ++ * This is useful to pass an integer instead of a pointer to a callback. ++ * ++ * GINT_TO_POINTER(i), GUINT_TO_POINTER(i) ++ * GPOINTER_TO_INT(p), GPOINTER_TO_UINT(p) ++ * ++ * Finally, it provide the following wrappers to STDC functions: ++ * ++ * g_ATEXIT ++ * To register hooks which are executed on exit(). ++ * Usually a wrapper for STDC atexit. ++ * ++ * void *g_memmove(void *dest, const void *src, guint count); ++ * A wrapper for STDC memmove, or an implementation, if memmove doesn't ++ * exist. The prototype looks like the above, give or take a const, ++ * or size_t. ++ */ ++#include <glibconfig.h> ++ ++/* include varargs functions for assertment macros ++ */ ++#include <stdarg.h> ++ ++#define G_DIR_SEPARATOR '/' ++#define G_DIR_SEPARATOR_S "/" ++#define G_SEARCHPATH_SEPARATOR ':' ++#define G_SEARCHPATH_SEPARATOR_S ":" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++ ++/* Provide definitions for some commonly used macros. ++ * Some of them are only provided if they haven't already ++ * been defined. It is assumed that if they are already ++ * defined then the current definition is correct. ++ */ ++#ifndef NULL ++#define NULL ((void*) 0) ++#endif ++ ++#ifndef FALSE ++#define FALSE (0) ++#endif ++ ++#ifndef TRUE ++#define TRUE (!FALSE) ++#endif ++ ++#undef MAX ++#define MAX(a, b) (((a) > (b)) ? (a) : (b)) ++ ++#undef MIN ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++ ++#undef ABS ++#define ABS(a) (((a) < 0) ? -(a) : (a)) ++ ++#undef CLAMP ++#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) ++ ++ ++/* Define G_VA_COPY() to do the right thing for copying va_list variables. ++ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy. ++ */ ++#if !defined (G_VA_COPY) ++# if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32)) ++# define G_VA_COPY(ap1, ap2) (*(ap1) = *(ap2)) ++# elif defined (G_VA_COPY_AS_ARRAY) ++# define G_VA_COPY(ap1, ap2) g_memmove ((ap1), (ap2), sizeof (va_list)) ++# else /* va_list is a pointer */ ++# define G_VA_COPY(ap1, ap2) ((ap1) = (ap2)) ++# endif /* va_list is a pointer */ ++#endif /* !G_VA_COPY */ ++ ++ ++/* Provide convenience macros for handling structure ++ * fields through their offsets. ++ */ ++#define G_STRUCT_OFFSET(struct_type, member) \ ++ ((gulong) ((gchar*) &((struct_type*) 0)->member)) ++#define G_STRUCT_MEMBER_P(struct_p, struct_offset) \ ++ ((gpointer) ((gchar*) (struct_p) + (gulong) (struct_offset))) ++#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset) \ ++ (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset))) ++ ++ ++/* inlining hassle. for compilers that don't allow the `inline' keyword, ++ * mostly because of strict ANSI C compliance or dumbness, we try to fall ++ * back to either `__inline__' or `__inline'. ++ * we define G_CAN_INLINE, if the compiler seems to be actually ++ * *capable* to do function inlining, in which case inline function bodys ++ * do make sense. we also define G_INLINE_FUNC to properly export the ++ * function prototypes if no inlining can be performed. ++ * we special case most of the stuff, so inline functions can have a normal ++ * implementation by defining G_INLINE_FUNC to extern and G_CAN_INLINE to 1. ++ */ ++#ifndef G_INLINE_FUNC ++# define G_CAN_INLINE 1 ++#endif ++#ifdef G_HAVE_INLINE ++# if defined (__GNUC__) && defined (__STRICT_ANSI__) ++# undef inline ++# define inline __inline__ ++# endif ++#else /* !G_HAVE_INLINE */ ++# undef inline ++# if defined (G_HAVE___INLINE__) ++# define inline __inline__ ++# else /* !inline && !__inline__ */ ++# if defined (G_HAVE___INLINE) ++# define inline __inline ++# else /* !inline && !__inline__ && !__inline */ ++# define inline /* don't inline, then */ ++# ifndef G_INLINE_FUNC ++# undef G_CAN_INLINE ++# endif ++# endif ++# endif ++#endif ++#ifndef G_INLINE_FUNC ++# ifdef __GNUC__ ++# ifdef __OPTIMIZE__ ++# define G_INLINE_FUNC extern inline ++# else ++# undef G_CAN_INLINE ++# define G_INLINE_FUNC extern ++# endif ++# else /* !__GNUC__ */ ++# ifdef G_CAN_INLINE ++# define G_INLINE_FUNC static inline ++# else ++# define G_INLINE_FUNC extern ++# endif ++# endif /* !__GNUC__ */ ++#endif /* !G_INLINE_FUNC */ ++ ++ ++/* Provide simple macro statement wrappers (adapted from Perl): ++ * G_STMT_START { statements; } G_STMT_END; ++ * can be used as a single statement, as in ++ * if (x) G_STMT_START { ... } G_STMT_END; else ... ++ * ++ * For gcc we will wrap the statements within `({' and `})' braces. ++ * For SunOS they will be wrapped within `if (1)' and `else (void) 0', ++ * and otherwise within `do' and `while (0)'. ++ */ ++#if !(defined (G_STMT_START) && defined (G_STMT_END)) ++# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) ++# define G_STMT_START (void)( ++# define G_STMT_END ) ++# else ++# if (defined (sun) || defined (__sun__)) ++# define G_STMT_START if (1) ++# define G_STMT_END else (void)0 ++# else ++# define G_STMT_START do ++# define G_STMT_END while (0) ++# endif ++# endif ++#endif ++ ++ ++/* Provide macros to feature the GCC function attribute. ++ */ ++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) ++#define G_GNUC_PRINTF( format_idx, arg_idx ) \ ++ __attribute__((format (printf, format_idx, arg_idx))) ++#define G_GNUC_SCANF( format_idx, arg_idx ) \ ++ __attribute__((format (scanf, format_idx, arg_idx))) ++#define G_GNUC_FORMAT( arg_idx ) \ ++ __attribute__((format_arg (arg_idx))) ++#define G_GNUC_NORETURN \ ++ __attribute__((noreturn)) ++#define G_GNUC_CONST \ ++ __attribute__((const)) ++#define G_GNUC_UNUSED \ ++ __attribute__((unused)) ++#else /* !__GNUC__ */ ++#define G_GNUC_PRINTF( format_idx, arg_idx ) ++#define G_GNUC_SCANF( format_idx, arg_idx ) ++#define G_GNUC_FORMAT( arg_idx ) ++#define G_GNUC_NORETURN ++#define G_GNUC_CONST ++#define G_GNUC_UNUSED ++#endif /* !__GNUC__ */ ++ ++ ++/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with ++ * macros, so we can refer to them as strings unconditionally. ++ */ ++#ifdef __GNUC__ ++#define G_GNUC_FUNCTION __FUNCTION__ ++#define G_GNUC_PRETTY_FUNCTION __PRETTY_FUNCTION__ ++#else /* !__GNUC__ */ ++#define G_GNUC_FUNCTION "" ++#define G_GNUC_PRETTY_FUNCTION "" ++#endif /* !__GNUC__ */ ++ ++/* we try to provide a usefull equivalent for ATEXIT if it is ++ * not defined, but use is actually abandoned. people should ++ * use g_atexit() instead. ++ */ ++#ifndef ATEXIT ++# define ATEXIT(proc) g_ATEXIT(proc) ++#else ++# define G_NATIVE_ATEXIT ++#endif /* ATEXIT */ ++ ++/* Hacker macro to place breakpoints for elected machines. ++ * Actual use is strongly deprecated of course ;) ++ */ ++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 ++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("int $03"); }G_STMT_END ++#elif defined (__alpha__) && defined (__GNUC__) && __GNUC__ >= 2 ++#define G_BREAKPOINT() G_STMT_START{ __asm__ __volatile__ ("bpt"); }G_STMT_END ++#else /* !__i386__ && !__alpha__ */ ++#define G_BREAKPOINT() ++#endif /* __i386__ */ ++ ++ ++/* Provide macros for easily allocating memory. The macros ++ * will cast the allocated memory to the specified type ++ * in order to avoid compiler warnings. (Makes the code neater). ++ */ ++ ++#ifdef __DMALLOC_H__ ++# define g_new(type, count) (ALLOC (type, count)) ++# define g_new0(type, count) (CALLOC (type, count)) ++# define g_renew(type, mem, count) (REALLOC (mem, type, count)) ++#else /* __DMALLOC_H__ */ ++# define g_new(type, count) \ ++ ((type *) g_malloc ((unsigned) sizeof (type) * (count))) ++# define g_new0(type, count) \ ++ ((type *) g_malloc0 ((unsigned) sizeof (type) * (count))) ++# define g_renew(type, mem, count) \ ++ ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count))) ++#endif /* __DMALLOC_H__ */ ++ ++#define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \ ++ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \ ++ sizeof (type), \ ++ sizeof (type) * (pre_alloc), \ ++ (alloc_type)) \ ++) ++#define g_chunk_new(type, chunk) ( \ ++ (type *) g_mem_chunk_alloc (chunk) \ ++) ++#define g_chunk_new0(type, chunk) ( \ ++ (type *) g_mem_chunk_alloc0 (chunk) \ ++) ++#define g_chunk_free(mem, mem_chunk) G_STMT_START { \ ++ g_mem_chunk_free ((mem_chunk), (mem)); \ ++} G_STMT_END ++ ++ ++#define g_string(x) #x ++ ++ ++/* Provide macros for error handling. The "assert" macros will ++ * exit on failure. The "return" macros will exit the current ++ * function. Two different definitions are given for the macros ++ * if G_DISABLE_ASSERT is not defined, in order to support gcc's ++ * __PRETTY_FUNCTION__ capability. ++ */ ++ ++#ifdef G_DISABLE_ASSERT ++ ++#define g_assert(expr) ++#define g_assert_not_reached() ++ ++#else /* !G_DISABLE_ASSERT */ ++ ++#ifdef __GNUC__ ++ ++#define g_assert(expr) G_STMT_START{ \ ++ if (!(expr)) \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_ERROR, \ ++ "file %s: line %d (%s): assertion failed: (%s)", \ ++ __FILE__, \ ++ __LINE__, \ ++ __PRETTY_FUNCTION__, \ ++ #expr); }G_STMT_END ++ ++#define g_assert_not_reached() G_STMT_START{ \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_ERROR, \ ++ "file %s: line %d (%s): should not be reached", \ ++ __FILE__, \ ++ __LINE__, \ ++ __PRETTY_FUNCTION__); }G_STMT_END ++ ++#else /* !__GNUC__ */ ++ ++#define g_assert(expr) G_STMT_START{ \ ++ if (!(expr)) \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_ERROR, \ ++ "file %s: line %d: assertion failed: (%s)", \ ++ __FILE__, \ ++ __LINE__, \ ++ #expr); }G_STMT_END ++ ++#define g_assert_not_reached() G_STMT_START{ \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_ERROR, \ ++ "file %s: line %d: should not be reached", \ ++ __FILE__, \ ++ __LINE__); }G_STMT_END ++ ++#endif /* __GNUC__ */ ++ ++#endif /* !G_DISABLE_ASSERT */ ++ ++ ++#ifdef __KORBIT__ ++ ++#define g_return_if_fail(expr) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ return; \ ++ }; }G_STMT_END ++ ++#define g_return_val_if_fail(expr,val) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ return val; \ ++ }; }G_STMT_END ++ ++#else /* !__KORBIT__ */ ++ ++#ifdef G_DISABLE_CHECKS ++ ++#define g_return_if_fail(expr) ++#define g_return_val_if_fail(expr,val) ++ ++#else /* !G_DISABLE_CHECKS */ ++ ++#ifdef __GNUC__ ++ ++#define g_return_if_fail(expr) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d (%s): assertion `%s' failed.", \ ++ __FILE__, \ ++ __LINE__, \ ++ __PRETTY_FUNCTION__, \ ++ #expr); \ ++ return; \ ++ }; }G_STMT_END ++ ++#define g_return_val_if_fail(expr,val) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d (%s): assertion `%s' failed.", \ ++ __FILE__, \ ++ __LINE__, \ ++ __PRETTY_FUNCTION__, \ ++ #expr); \ ++ return val; \ ++ }; }G_STMT_END ++ ++#else /* !__GNUC__ */ ++ ++#define g_return_if_fail(expr) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d: assertion `%s' failed.", \ ++ __FILE__, \ ++ __LINE__, \ ++ #expr); \ ++ return; \ ++ }; }G_STMT_END ++ ++#define g_return_val_if_fail(expr, val) G_STMT_START{ \ ++ if (!(expr)) \ ++ { \ ++ g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_CRITICAL, \ ++ "file %s: line %d: assertion `%s' failed.", \ ++ __FILE__, \ ++ __LINE__, \ ++ #expr); \ ++ return val; \ ++ }; }G_STMT_END ++ ++#endif /* !__GNUC__ */ ++ ++#endif /* !G_DISABLE_CHECKS */ ++ ++#endif /* !__KORBIT__ */ ++ ++ ++/* Provide type definitions for commonly used types. ++ * These are useful because a "gint8" can be adjusted ++ * to be 1 byte (8 bits) on all platforms. Similarly and ++ * more importantly, "gint32" can be adjusted to be ++ * 4 bytes (32 bits) on all platforms. ++ */ ++ ++typedef char gchar; ++typedef short gshort; ++typedef long glong; ++typedef int gint; ++typedef gint gboolean; ++ ++typedef unsigned char guchar; ++typedef unsigned short gushort; ++typedef unsigned long gulong; ++typedef unsigned int guint; ++ ++typedef float gfloat; ++typedef double gdouble; ++ ++/* HAVE_LONG_DOUBLE doesn't work correctly on all platforms. ++ * Since gldouble isn't used anywhere, just disable it for now */ ++ ++#if 0 ++#ifdef HAVE_LONG_DOUBLE ++typedef long double gldouble; ++#else /* HAVE_LONG_DOUBLE */ ++typedef double gldouble; ++#endif /* HAVE_LONG_DOUBLE */ ++#endif /* 0 */ ++ ++typedef void* gpointer; ++typedef const void *gconstpointer; ++ ++ ++typedef gint32 gssize; ++typedef guint32 gsize; ++typedef guint32 GQuark; ++typedef gint32 GTime; ++ ++ ++/* Portable endian checks and conversions ++ * ++ * glibconfig.h defines G_BYTE_ORDER which expands to one of ++ * the below macros. ++ */ ++#define G_LITTLE_ENDIAN 1234 ++#define G_BIG_ENDIAN 4321 ++#define G_PDP_ENDIAN 3412 /* unused, need specific PDP check */ ++ ++ ++/* Basic bit swapping functions ++ */ ++#define GUINT16_SWAP_LE_BE_CONSTANT(val) ((guint16) ( \ ++ (((guint16) (val) & (guint16) 0x00ffU) << 8) | \ ++ (((guint16) (val) & (guint16) 0xff00U) >> 8))) ++#define GUINT32_SWAP_LE_BE_CONSTANT(val) ((guint32) ( \ ++ (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \ ++ (((guint32) (val) & (guint32) 0x0000ff00U) << 8) | \ ++ (((guint32) (val) & (guint32) 0x00ff0000U) >> 8) | \ ++ (((guint32) (val) & (guint32) 0xff000000U) >> 24))) ++ ++/* Intel specific stuff for speed ++ */ ++#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 ++# define GUINT16_SWAP_LE_BE_X86(val) \ ++ (__extension__ \ ++ ({ register guint16 __v; \ ++ if (__builtin_constant_p (val)) \ ++ __v = GUINT16_SWAP_LE_BE_CONSTANT (val); \ ++ else \ ++ __asm__ __const__ ("rorw $8, %w0" \ ++ : "=r" (__v) \ ++ : "0" ((guint16) (val))); \ ++ __v; })) ++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_X86 (val)) ++# if !defined(__i486__) && !defined(__i586__) \ ++ && !defined(__pentium__) && !defined(__i686__) && !defined(__pentiumpro__) ++# define GUINT32_SWAP_LE_BE_X86(val) \ ++ (__extension__ \ ++ ({ register guint32 __v; \ ++ if (__builtin_constant_p (val)) \ ++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \ ++ else \ ++ __asm__ __const__ ("rorw $8, %w0\n\t" \ ++ "rorl $16, %0\n\t" \ ++ "rorw $8, %w0" \ ++ : "=r" (__v) \ ++ : "0" ((guint32) (val))); \ ++ __v; })) ++# else /* 486 and higher has bswap */ ++# define GUINT32_SWAP_LE_BE_X86(val) \ ++ (__extension__ \ ++ ({ register guint32 __v; \ ++ if (__builtin_constant_p (val)) \ ++ __v = GUINT32_SWAP_LE_BE_CONSTANT (val); \ ++ else \ ++ __asm__ __const__ ("bswap %0" \ ++ : "=r" (__v) \ ++ : "0" ((guint32) (val))); \ ++ __v; })) ++# endif /* processor specific 32-bit stuff */ ++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86 (val)) ++#else /* !__i386__ */ ++# define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val)) ++# define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val)) ++#endif /* __i386__ */ ++ ++#ifdef G_HAVE_GINT64 ++# define GUINT64_SWAP_LE_BE_CONSTANT(val) ((guint64) ( \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x00000000000000ffU)) << 56) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x000000000000ff00U)) << 40) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x0000000000ff0000U)) << 24) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x00000000ff000000U)) << 8) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x000000ff00000000U)) >> 8) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x0000ff0000000000U)) >> 24) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0x00ff000000000000U)) >> 40) | \ ++ (((guint64) (val) & \ ++ (guint64) G_GINT64_CONSTANT(0xff00000000000000U)) >> 56))) ++# if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 ++# define GUINT64_SWAP_LE_BE_X86(val) \ ++ (__extension__ \ ++ ({ union { guint64 __ll; \ ++ guint32 __l[2]; } __r; \ ++ if (__builtin_constant_p (val)) \ ++ __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (val); \ ++ else \ ++ { \ ++ union { guint64 __ll; \ ++ guint32 __l[2]; } __w; \ ++ __w.__ll = ((guint64) val); \ ++ __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]); \ ++ __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]); \ ++ } \ ++ __r.__ll; })) ++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86 (val)) ++# else /* !__i386__ */ ++# define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT(val)) ++# endif ++#endif ++ ++#define GUINT16_SWAP_LE_PDP(val) ((guint16) (val)) ++#define GUINT16_SWAP_BE_PDP(val) (GUINT16_SWAP_LE_BE (val)) ++#define GUINT32_SWAP_LE_PDP(val) ((guint32) ( \ ++ (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \ ++ (((guint32) (val) & (guint32) 0xffff0000U) >> 16))) ++#define GUINT32_SWAP_BE_PDP(val) ((guint32) ( \ ++ (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \ ++ (((guint32) (val) & (guint32) 0xff00ff00U) >> 8))) ++ ++/* The G*_TO_?E() macros are defined in glibconfig.h. ++ * The transformation is symmetric, so the FROM just maps to the TO. ++ */ ++#define GINT16_FROM_LE(val) (GINT16_TO_LE (val)) ++#define GUINT16_FROM_LE(val) (GUINT16_TO_LE (val)) ++#define GINT16_FROM_BE(val) (GINT16_TO_BE (val)) ++#define GUINT16_FROM_BE(val) (GUINT16_TO_BE (val)) ++#define GINT32_FROM_LE(val) (GINT32_TO_LE (val)) ++#define GUINT32_FROM_LE(val) (GUINT32_TO_LE (val)) ++#define GINT32_FROM_BE(val) (GINT32_TO_BE (val)) ++#define GUINT32_FROM_BE(val) (GUINT32_TO_BE (val)) ++ ++#ifdef G_HAVE_GINT64 ++#define GINT64_FROM_LE(val) (GINT64_TO_LE (val)) ++#define GUINT64_FROM_LE(val) (GUINT64_TO_LE (val)) ++#define GINT64_FROM_BE(val) (GINT64_TO_BE (val)) ++#define GUINT64_FROM_BE(val) (GUINT64_TO_BE (val)) ++#endif ++ ++#define GLONG_FROM_LE(val) (GLONG_TO_LE (val)) ++#define GULONG_FROM_LE(val) (GULONG_TO_LE (val)) ++#define GLONG_FROM_BE(val) (GLONG_TO_BE (val)) ++#define GULONG_FROM_BE(val) (GULONG_TO_BE (val)) ++ ++#define GINT_FROM_LE(val) (GINT_TO_LE (val)) ++#define GUINT_FROM_LE(val) (GUINT_TO_LE (val)) ++#define GINT_FROM_BE(val) (GINT_TO_BE (val)) ++#define GUINT_FROM_BE(val) (GUINT_TO_BE (val)) ++ ++ ++/* Portable versions of host-network order stuff ++ */ ++#define g_ntohl(val) (GUINT32_FROM_BE (val)) ++#define g_ntohs(val) (GUINT16_FROM_BE (val)) ++#define g_htonl(val) (GUINT32_TO_BE (val)) ++#define g_htons(val) (GUINT16_TO_BE (val)) ++ ++ ++/* Glib version. ++ * we prefix variable declarations so they can ++ * properly get exported in windows dlls. ++ */ ++#define GUTILS_C_VAR extern ++ ++ ++GUTILS_C_VAR const guint glib_major_version; ++GUTILS_C_VAR const guint glib_minor_version; ++GUTILS_C_VAR const guint glib_micro_version; ++GUTILS_C_VAR const guint glib_interface_age; ++GUTILS_C_VAR const guint glib_binary_age; ++ ++#define GLIB_CHECK_VERSION(major,minor,micro) \ ++ (GLIB_MAJOR_VERSION > (major) || \ ++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \ ++ (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \ ++ GLIB_MICRO_VERSION >= (micro))) ++ ++/* Forward declarations of glib types. ++ */ ++typedef struct _GAllocator GAllocator; ++typedef struct _GArray GArray; ++typedef struct _GByteArray GByteArray; ++typedef struct _GDebugKey GDebugKey; ++typedef struct _GHashTable GHashTable; ++typedef struct _GList GList; ++typedef struct _GMemChunk GMemChunk; ++typedef struct _GNode GNode; ++typedef struct _GPtrArray GPtrArray; ++typedef struct _GSList GSList; ++typedef struct _GString GString; ++typedef struct _GStringChunk GStringChunk; ++typedef struct _GTree GTree; ++typedef struct _GTuples GTuples; ++ ++/* Tree traverse flags */ ++typedef enum ++{ ++ G_TRAVERSE_LEAFS = 1 << 0, ++ G_TRAVERSE_NON_LEAFS = 1 << 1, ++ G_TRAVERSE_ALL = G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS, ++ G_TRAVERSE_MASK = 0x03 ++} GTraverseFlags; ++ ++/* Tree traverse orders */ ++typedef enum ++{ ++ G_IN_ORDER, ++ G_PRE_ORDER, ++ G_POST_ORDER, ++ G_LEVEL_ORDER ++} GTraverseType; ++ ++/* Log level shift offset for user defined ++ * log levels (0-7 are used by GLib). ++ */ ++#define G_LOG_LEVEL_USER_SHIFT (8) ++ ++/* Glib log levels and flags. ++ */ ++typedef enum ++{ ++ /* log flags */ ++ G_LOG_FLAG_RECURSION = 1 << 0, ++ G_LOG_FLAG_FATAL = 1 << 1, ++ ++ /* GLib log levels */ ++ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */ ++ G_LOG_LEVEL_CRITICAL = 1 << 3, ++ G_LOG_LEVEL_WARNING = 1 << 4, ++ G_LOG_LEVEL_MESSAGE = 1 << 5, ++ G_LOG_LEVEL_INFO = 1 << 6, ++ G_LOG_LEVEL_DEBUG = 1 << 7, ++ ++ G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL) ++} GLogLevelFlags; ++ ++/* GLib log levels that are considered fatal by default */ ++#define G_LOG_FATAL_MASK (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR) ++ ++ ++typedef gint (*GCompareFunc) (gconstpointer a, ++ gconstpointer b); ++typedef gchar* (*GCompletionFunc) (gpointer); ++typedef void (*GDestroyNotify) (gpointer data); ++typedef void (*GDataForeachFunc) (GQuark key_id, ++ gpointer data, ++ gpointer user_data); ++typedef void (*GFunc) (gpointer data, ++ gpointer user_data); ++typedef guint (*GHashFunc) (gconstpointer key); ++typedef void (*GFreeFunc) (gpointer data); ++typedef void (*GHFunc) (gpointer key, ++ gpointer value, ++ gpointer user_data); ++typedef gboolean (*GHRFunc) (gpointer key, ++ gpointer value, ++ gpointer user_data); ++typedef void (*GLogFunc) (const gchar *log_domain, ++ GLogLevelFlags log_level, ++ const gchar *message, ++ gpointer user_data); ++typedef gboolean (*GNodeTraverseFunc) (GNode *node, ++ gpointer data); ++typedef void (*GNodeForeachFunc) (GNode *node, ++ gpointer data); ++typedef gint (*GSearchFunc) (gpointer key, ++ gpointer data); ++typedef gint (*GTraverseFunc) (gpointer key, ++ gpointer value, ++ gpointer data); ++typedef void (*GVoidFunc) (void); ++ ++ ++struct _GList ++{ ++ gpointer data; ++ GList *next; ++ GList *prev; ++}; ++ ++struct _GSList ++{ ++ gpointer data; ++ GSList *next; ++}; ++ ++struct _GString ++{ ++ gchar *str; ++ gint len; ++}; ++ ++struct _GArray ++{ ++ gchar *data; ++ guint len; ++}; ++ ++struct _GByteArray ++{ ++ guint8 *data; ++ guint len; ++}; ++ ++struct _GPtrArray ++{ ++ gpointer *pdata; ++ guint len; ++}; ++ ++struct _GTuples ++{ ++ guint len; ++}; ++ ++struct _GDebugKey ++{ ++ gchar *key; ++ guint value; ++}; ++ ++ ++/* Doubly linked lists ++ */ ++void g_list_push_allocator (GAllocator *allocator); ++void g_list_pop_allocator (void); ++GList* g_list_alloc (void); ++void g_list_free (GList *list); ++void g_list_free_1 (GList *list); ++GList* g_list_append (GList *list, ++ gpointer data); ++GList* g_list_prepend (GList *list, ++ gpointer data); ++GList* g_list_insert (GList *list, ++ gpointer data, ++ gint position); ++GList* g_list_insert_sorted (GList *list, ++ gpointer data, ++ GCompareFunc func); ++GList* g_list_concat (GList *list1, ++ GList *list2); ++GList* g_list_remove (GList *list, ++ gpointer data); ++GList* g_list_remove_link (GList *list, ++ GList *llink); ++GList* g_list_reverse (GList *list); ++GList* g_list_copy (GList *list); ++GList* g_list_nth (GList *list, ++ guint n); ++GList* g_list_find (GList *list, ++ gpointer data); ++GList* g_list_find_custom (GList *list, ++ gpointer data, ++ GCompareFunc func); ++gint g_list_position (GList *list, ++ GList *llink); ++gint g_list_index (GList *list, ++ gpointer data); ++GList* g_list_last (GList *list); ++GList* g_list_first (GList *list); ++guint g_list_length (GList *list); ++void g_list_foreach (GList *list, ++ GFunc func, ++ gpointer user_data); ++GList* g_list_sort (GList *list, ++ GCompareFunc compare_func); ++gpointer g_list_nth_data (GList *list, ++ guint n); ++#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL) ++#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL) ++ ++ ++/* Singly linked lists ++ */ ++void g_slist_push_allocator (GAllocator *allocator); ++void g_slist_pop_allocator (void); ++GSList* g_slist_alloc (void); ++void g_slist_free (GSList *list); ++void g_slist_free_1 (GSList *list); ++GSList* g_slist_append (GSList *list, ++ gpointer data); ++GSList* g_slist_prepend (GSList *list, ++ gpointer data); ++GSList* g_slist_insert (GSList *list, ++ gpointer data, ++ gint position); ++GSList* g_slist_insert_sorted (GSList *list, ++ gpointer data, ++ GCompareFunc func); ++GSList* g_slist_concat (GSList *list1, ++ GSList *list2); ++GSList* g_slist_remove (GSList *list, ++ gpointer data); ++GSList* g_slist_remove_link (GSList *list, ++ GSList *llink); ++GSList* g_slist_reverse (GSList *list); ++GSList* g_slist_copy (GSList *list); ++GSList* g_slist_nth (GSList *list, ++ guint n); ++GSList* g_slist_find (GSList *list, ++ gpointer data); ++GSList* g_slist_find_custom (GSList *list, ++ gpointer data, ++ GCompareFunc func); ++gint g_slist_position (GSList *list, ++ GSList *llink); ++gint g_slist_index (GSList *list, ++ gpointer data); ++GSList* g_slist_last (GSList *list); ++guint g_slist_length (GSList *list); ++void g_slist_foreach (GSList *list, ++ GFunc func, ++ gpointer user_data); ++GSList* g_slist_sort (GSList *list, ++ GCompareFunc compare_func); ++gpointer g_slist_nth_data (GSList *list, ++ guint n); ++#define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL) ++ ++ ++/* Hash tables ++ */ ++GHashTable* g_hash_table_new (GHashFunc hash_func, ++ GCompareFunc key_compare_func); ++void g_hash_table_destroy (GHashTable *hash_table); ++void g_hash_table_insert (GHashTable *hash_table, ++ gpointer key, ++ gpointer value); ++void g_hash_table_remove (GHashTable *hash_table, ++ gconstpointer key); ++gpointer g_hash_table_lookup (GHashTable *hash_table, ++ gconstpointer key); ++gboolean g_hash_table_lookup_extended(GHashTable *hash_table, ++ gconstpointer lookup_key, ++ gpointer *orig_key, ++ gpointer *value); ++void g_hash_table_freeze (GHashTable *hash_table); ++void g_hash_table_thaw (GHashTable *hash_table); ++void g_hash_table_foreach (GHashTable *hash_table, ++ GHFunc func, ++ gpointer user_data); ++guint g_hash_table_foreach_remove (GHashTable *hash_table, ++ GHRFunc func, ++ gpointer user_data); ++guint g_hash_table_size (GHashTable *hash_table); ++ ++ ++ ++ ++/* Balanced binary trees ++ */ ++GTree* g_tree_new (GCompareFunc key_compare_func); ++void g_tree_destroy (GTree *tree); ++void g_tree_insert (GTree *tree, ++ gpointer key, ++ gpointer value); ++void g_tree_remove (GTree *tree, ++ gpointer key); ++gpointer g_tree_lookup (GTree *tree, ++ gpointer key); ++void g_tree_traverse (GTree *tree, ++ GTraverseFunc traverse_func, ++ GTraverseType traverse_type, ++ gpointer data); ++gpointer g_tree_search (GTree *tree, ++ GSearchFunc search_func, ++ gpointer data); ++gint g_tree_height (GTree *tree); ++gint g_tree_nnodes (GTree *tree); ++ ++ ++ ++/* N-way tree implementation ++ */ ++struct _GNode ++{ ++ gpointer data; ++ GNode *next; ++ GNode *prev; ++ GNode *parent; ++ GNode *children; ++}; ++ ++#define G_NODE_IS_ROOT(node) (((GNode*) (node))->parent == NULL && \ ++ ((GNode*) (node))->prev == NULL && \ ++ ((GNode*) (node))->next == NULL) ++#define G_NODE_IS_LEAF(node) (((GNode*) (node))->children == NULL) ++ ++void g_node_push_allocator (GAllocator *allocator); ++void g_node_pop_allocator (void); ++GNode* g_node_new (gpointer data); ++void g_node_destroy (GNode *root); ++void g_node_unlink (GNode *node); ++GNode* g_node_insert (GNode *parent, ++ gint position, ++ GNode *node); ++GNode* g_node_insert_before (GNode *parent, ++ GNode *sibling, ++ GNode *node); ++GNode* g_node_prepend (GNode *parent, ++ GNode *node); ++guint g_node_n_nodes (GNode *root, ++ GTraverseFlags flags); ++GNode* g_node_get_root (GNode *node); ++gboolean g_node_is_ancestor (GNode *node, ++ GNode *descendant); ++guint g_node_depth (GNode *node); ++GNode* g_node_find (GNode *root, ++ GTraverseType order, ++ GTraverseFlags flags, ++ gpointer data); ++ ++/* convenience macros */ ++#define g_node_append(parent, node) \ ++ g_node_insert_before ((parent), NULL, (node)) ++#define g_node_insert_data(parent, position, data) \ ++ g_node_insert ((parent), (position), g_node_new (data)) ++#define g_node_insert_data_before(parent, sibling, data) \ ++ g_node_insert_before ((parent), (sibling), g_node_new (data)) ++#define g_node_prepend_data(parent, data) \ ++ g_node_prepend ((parent), g_node_new (data)) ++#define g_node_append_data(parent, data) \ ++ g_node_insert_before ((parent), NULL, g_node_new (data)) ++ ++/* traversal function, assumes that `node' is root ++ * (only traverses `node' and its subtree). ++ * this function is just a high level interface to ++ * low level traversal functions, optimized for speed. ++ */ ++void g_node_traverse (GNode *root, ++ GTraverseType order, ++ GTraverseFlags flags, ++ gint max_depth, ++ GNodeTraverseFunc func, ++ gpointer data); ++ ++/* return the maximum tree height starting with `node', this is an expensive ++ * operation, since we need to visit all nodes. this could be shortened by ++ * adding `guint height' to struct _GNode, but then again, this is not very ++ * often needed, and would make g_node_insert() more time consuming. ++ */ ++guint g_node_max_height (GNode *root); ++ ++void g_node_children_foreach (GNode *node, ++ GTraverseFlags flags, ++ GNodeForeachFunc func, ++ gpointer data); ++void g_node_reverse_children (GNode *node); ++guint g_node_n_children (GNode *node); ++GNode* g_node_nth_child (GNode *node, ++ guint n); ++GNode* g_node_last_child (GNode *node); ++GNode* g_node_find_child (GNode *node, ++ GTraverseFlags flags, ++ gpointer data); ++gint g_node_child_position (GNode *node, ++ GNode *child); ++gint g_node_child_index (GNode *node, ++ gpointer data); ++ ++GNode* g_node_first_sibling (GNode *node); ++GNode* g_node_last_sibling (GNode *node); ++ ++#define g_node_prev_sibling(node) ((node) ? \ ++ ((GNode*) (node))->prev : NULL) ++#define g_node_next_sibling(node) ((node) ? \ ++ ((GNode*) (node))->next : NULL) ++#define g_node_first_child(node) ((node) ? \ ++ ((GNode*) (node))->children : NULL) ++ ++ ++ ++/* Fatal error handlers. ++ * g_on_error_query() will prompt the user to either ++ * [E]xit, [H]alt, [P]roceed or show [S]tack trace. ++ * g_on_error_stack_trace() invokes gdb, which attaches to the current ++ * process and shows a stack trace. ++ * These function may cause different actions on non-unix platforms. ++ * The prg_name arg is required by gdb to find the executable, if it is ++ * passed as NULL, g_on_error_query() will try g_get_prgname(). ++ */ ++void g_on_error_query (const gchar *prg_name); ++void g_on_error_stack_trace (const gchar *prg_name); ++ ++ ++/* Logging mechanism ++ */ ++extern const gchar *g_log_domain_glib; ++guint g_log_set_handler (const gchar *log_domain, ++ GLogLevelFlags log_levels, ++ GLogFunc log_func, ++ gpointer user_data); ++void g_log_remove_handler (const gchar *log_domain, ++ guint handler_id); ++void g_log_default_handler (const gchar *log_domain, ++ GLogLevelFlags log_level, ++ const gchar *message, ++ gpointer unused_data); ++#ifdef __KORBIT__ ++#define g_log(log_domain, log_level, format, args...) \ ++G_STMT_START { printf(format, ##args); printf("\n"); } G_STMT_END ++#define g_logv(log_domain, log_level, format, args...) ++#else /* !__KORBIT__ */ ++void g_log (const gchar *log_domain, ++ GLogLevelFlags log_level, ++ const gchar *format, ++ ...) G_GNUC_PRINTF (3, 4); ++void g_logv (const gchar *log_domain, ++ GLogLevelFlags log_level, ++ const gchar *format, ++ va_list args); ++#endif /* !__KORBIT__ */ ++GLogLevelFlags g_log_set_fatal_mask (const gchar *log_domain, ++ GLogLevelFlags fatal_mask); ++GLogLevelFlags g_log_set_always_fatal (GLogLevelFlags fatal_mask); ++#ifndef G_LOG_DOMAIN ++#define G_LOG_DOMAIN ((gchar*) 0) ++#endif /* G_LOG_DOMAIN */ ++#ifdef __GNUC__ ++#define g_error(format, args...) g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_ERROR, \ ++ format, ##args) ++#define g_message(format, args...) g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_MESSAGE, \ ++ format, ##args) ++#define g_warning(format, args...) g_log (G_LOG_DOMAIN, \ ++ G_LOG_LEVEL_WARNING, \ ++ format, ##args) ++#else /* !__GNUC__ */ ++static void ++g_error (const gchar *format, ++ ...) ++{ ++ va_list args; ++ va_start (args, format); ++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args); ++ va_end (args); ++} ++static void ++g_message (const gchar *format, ++ ...) ++{ ++ va_list args; ++ va_start (args, format); ++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args); ++ va_end (args); ++} ++static void ++g_warning (const gchar *format, ++ ...) ++{ ++ va_list args; ++ va_start (args, format); ++ g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args); ++ va_end (args); ++} ++#endif /* !__GNUC__ */ ++ ++typedef void (*GPrintFunc) (const gchar *string); ++#ifdef __KORBIT__ ++#define g_print(format, args...) printf(format, ##args) ++#else ++void g_print (const gchar *format, ++ ...) G_GNUC_PRINTF (1, 2); ++#endif ++GPrintFunc g_set_print_handler (GPrintFunc func); ++void g_printerr (const gchar *format, ++ ...) G_GNUC_PRINTF (1, 2); ++GPrintFunc g_set_printerr_handler (GPrintFunc func); ++ ++/* deprecated compatibility functions, use g_log_set_handler() instead */ ++typedef void (*GErrorFunc) (const gchar *str); ++typedef void (*GWarningFunc) (const gchar *str); ++GErrorFunc g_set_error_handler (GErrorFunc func); ++GWarningFunc g_set_warning_handler (GWarningFunc func); ++GPrintFunc g_set_message_handler (GPrintFunc func); ++ ++ ++gpointer g_malloc (gulong size); ++gpointer g_malloc0 (gulong size); ++gpointer g_realloc (gpointer mem, ++ gulong size); ++void g_free (gpointer mem); ++ ++/* Generic allocators ++ */ ++GAllocator* g_allocator_new (const gchar *name, ++ guint n_preallocs); ++void g_allocator_free (GAllocator *allocator); ++ ++#define G_ALLOCATOR_LIST (1) ++#define G_ALLOCATOR_SLIST (2) ++#define G_ALLOCATOR_NODE (3) ++ ++ ++/* "g_mem_chunk_new" creates a new memory chunk. ++ * Memory chunks are used to allocate pieces of memory which are ++ * always the same size. Lists are a good example of such a data type. ++ * The memory chunk allocates and frees blocks of memory as needed. ++ * Just be sure to call "g_mem_chunk_free" and not "g_free" on data ++ * allocated in a mem chunk. ("g_free" will most likely cause a seg ++ * fault...somewhere). ++ * ++ * Oh yeah, GMemChunk is an opaque data type. (You don't really ++ * want to know what's going on inside do you?) ++ */ ++ ++/* ALLOC_ONLY MemChunk's can only allocate memory. The free operation ++ * is interpreted as a no op. ALLOC_ONLY MemChunk's save 4 bytes per ++ * atom. (They are also useful for lists which use MemChunk to allocate ++ * memory but are also part of the MemChunk implementation). ++ * ALLOC_AND_FREE MemChunk's can allocate and free memory. ++ */ ++ ++#define G_ALLOC_ONLY 1 ++#define G_ALLOC_AND_FREE 2 ++ ++GMemChunk* g_mem_chunk_new (gchar *name, ++ gint atom_size, ++ gulong area_size, ++ gint type); ++void g_mem_chunk_destroy (GMemChunk *mem_chunk); ++gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk); ++gpointer g_mem_chunk_alloc0 (GMemChunk *mem_chunk); ++void g_mem_chunk_free (GMemChunk *mem_chunk, ++ gpointer mem); ++void g_mem_chunk_clean (GMemChunk *mem_chunk); ++void g_mem_chunk_reset (GMemChunk *mem_chunk); ++void g_mem_chunk_print (GMemChunk *mem_chunk); ++void g_mem_chunk_info (void); ++ ++/* Ah yes...we have a "g_blow_chunks" function. ++ * "g_blow_chunks" simply compresses all the chunks. This operation ++ * consists of freeing every memory area that should be freed (but ++ * which we haven't gotten around to doing yet). And, no, ++ * "g_blow_chunks" doesn't follow the naming scheme, but it is a ++ * much better name than "g_mem_chunk_clean_all" or something ++ * similar. ++ */ ++void g_blow_chunks (void); ++ ++ ++/* String utility functions that modify a string argument or ++ * return a constant string that must not be freed. ++ */ ++#define G_STR_DELIMITERS "_-|> <." ++gchar* g_strdelimit (gchar *string, ++ const gchar *delimiters, ++ gchar new_delimiter); ++#ifndef __KORBIT__ ++gdouble g_strtod (const gchar *nptr, ++ gchar **endptr); ++#endif /* !__KORBIT__ */ ++gchar* g_strerror (gint errnum); ++gchar* g_strsignal (gint signum); ++gint g_strcasecmp (const gchar *s1, ++ const gchar *s2); ++gint g_strncasecmp (const gchar *s1, ++ const gchar *s2, ++ guint n); ++void g_strdown (gchar *string); ++void g_strup (gchar *string); ++void g_strreverse (gchar *string); ++/* removes leading spaces */ ++gchar* g_strchug (gchar *string); ++/* removes trailing spaces */ ++gchar* g_strchomp (gchar *string); ++/* removes leading & trailing spaces */ ++#define g_strstrip( string ) g_strchomp (g_strchug (string)) ++ ++/* String utility functions that return a newly allocated string which ++ * ought to be freed from the caller at some point. ++ */ ++gchar* g_strdup (const gchar *str); ++gchar* g_strdup_printf (const gchar *format, ++ ...) G_GNUC_PRINTF (1, 2); ++gchar* g_strdup_vprintf (const gchar *format, ++ va_list args); ++gchar* g_strndup (const gchar *str, ++ guint n); ++gchar* g_strnfill (guint length, ++ gchar fill_char); ++gchar* g_strconcat (const gchar *string1, ++ ...); /* NULL terminated */ ++gchar* g_strjoin (const gchar *separator, ++ ...); /* NULL terminated */ ++gchar* g_strescape (gchar *string); ++gpointer g_memdup (gconstpointer mem, ++ guint byte_size); ++ ++/* NULL terminated string arrays. ++ * g_strsplit() splits up string into max_tokens tokens at delim and ++ * returns a newly allocated string array. ++ * g_strjoinv() concatenates all of str_array's strings, sliding in an ++ * optional separator, the returned string is newly allocated. ++ * g_strfreev() frees the array itself and all of its strings. ++ */ ++gchar** g_strsplit (const gchar *string, ++ const gchar *delimiter, ++ gint max_tokens); ++gchar* g_strjoinv (const gchar *separator, ++ gchar **str_array); ++void g_strfreev (gchar **str_array); ++ ++ ++ ++/* calculate a string size, guarranteed to fit format + args. ++ */ ++guint g_printf_string_upper_bound (const gchar* format, ++ va_list args); ++ ++ ++/* Retrive static string info ++ */ ++gchar* g_get_user_name (void); ++gchar* g_get_real_name (void); ++gchar* g_get_home_dir (void); ++gchar* g_get_tmp_dir (void); ++gchar* g_get_prgname (void); ++void g_set_prgname (const gchar *prgname); ++ ++ ++/* Miscellaneous utility functions ++ */ ++guint g_parse_debug_string (const gchar *string, ++ GDebugKey *keys, ++ guint nkeys); ++gint g_snprintf (gchar *string, ++ gulong n, ++ gchar const *format, ++ ...) G_GNUC_PRINTF (3, 4); ++gint g_vsnprintf (gchar *string, ++ gulong n, ++ gchar const *format, ++ va_list args); ++gchar* g_basename (const gchar *file_name); ++/* Check if a file name is an absolute path */ ++gboolean g_path_is_absolute (const gchar *file_name); ++/* In case of absolute paths, skip the root part */ ++gchar* g_path_skip_root (gchar *file_name); ++ ++/* strings are newly allocated with g_malloc() */ ++gchar* g_dirname (const gchar *file_name); ++gchar* g_get_current_dir (void); ++gchar* g_getenv (const gchar *variable); ++ ++ ++/* we use a GLib function as a replacement for ATEXIT, so ++ * the programmer is not required to check the return value ++ * (if there is any in the implementation) and doesn't encounter ++ * missing include files. ++ */ ++void g_atexit (GVoidFunc func); ++ ++ ++/* Bit tests ++ */ ++G_INLINE_FUNC gint g_bit_nth_lsf (guint32 mask, ++ gint nth_bit); ++#ifdef G_CAN_INLINE ++G_INLINE_FUNC gint ++g_bit_nth_lsf (guint32 mask, ++ gint nth_bit) ++{ ++ do ++ { ++ nth_bit++; ++ if (mask & (1 << (guint) nth_bit)) ++ return nth_bit; ++ } ++ while (nth_bit < 32); ++ return -1; ++} ++#endif /* G_CAN_INLINE */ ++ ++G_INLINE_FUNC gint g_bit_nth_msf (guint32 mask, ++ gint nth_bit); ++#ifdef G_CAN_INLINE ++G_INLINE_FUNC gint ++g_bit_nth_msf (guint32 mask, ++ gint nth_bit) ++{ ++ if (nth_bit < 0) ++ nth_bit = 32; ++ do ++ { ++ nth_bit--; ++ if (mask & (1 << (guint) nth_bit)) ++ return nth_bit; ++ } ++ while (nth_bit > 0); ++ return -1; ++} ++#endif /* G_CAN_INLINE */ ++ ++G_INLINE_FUNC guint g_bit_storage (guint number); ++#ifdef G_CAN_INLINE ++G_INLINE_FUNC guint ++g_bit_storage (guint number) ++{ ++ register guint n_bits = 0; ++ ++ do ++ { ++ n_bits++; ++ number >>= 1; ++ } ++ while (number); ++ return n_bits; ++} ++#endif /* G_CAN_INLINE */ ++ ++/* String Chunks ++ */ ++GStringChunk* g_string_chunk_new (gint size); ++void g_string_chunk_free (GStringChunk *chunk); ++gchar* g_string_chunk_insert (GStringChunk *chunk, ++ const gchar *string); ++gchar* g_string_chunk_insert_const (GStringChunk *chunk, ++ const gchar *string); ++ ++ ++/* Strings ++ */ ++GString* g_string_new (const gchar *init); ++GString* g_string_sized_new (guint dfl_size); ++void g_string_free (GString *string, ++ gint free_segment); ++GString* g_string_assign (GString *lval, ++ const gchar *rval); ++GString* g_string_truncate (GString *string, ++ gint len); ++GString* g_string_append (GString *string, ++ const gchar *val); ++GString* g_string_append_c (GString *string, ++ gchar c); ++GString* g_string_prepend (GString *string, ++ const gchar *val); ++GString* g_string_prepend_c (GString *string, ++ gchar c); ++GString* g_string_insert (GString *string, ++ gint pos, ++ const gchar *val); ++GString* g_string_insert_c (GString *string, ++ gint pos, ++ gchar c); ++GString* g_string_erase (GString *string, ++ gint pos, ++ gint len); ++GString* g_string_down (GString *string); ++GString* g_string_up (GString *string); ++void g_string_sprintf (GString *string, ++ const gchar *format, ++ ...) G_GNUC_PRINTF (2, 3); ++void g_string_sprintfa (GString *string, ++ const gchar *format, ++ ...) G_GNUC_PRINTF (2, 3); ++ ++ ++/* Resizable arrays, remove fills any cleared spot and shortens the ++ * array, while preserving the order. remove_fast will distort the ++ * order by moving the last element to the position of the removed ++ */ ++ ++#define g_array_append_val(a,v) g_array_append_vals (a, &v, 1) ++#define g_array_prepend_val(a,v) g_array_prepend_vals (a, &v, 1) ++#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &v, 1) ++#define g_array_index(a,t,i) (((t*) (a)->data) [(i)]) ++ ++GArray* g_array_new (gboolean zero_terminated, ++ gboolean clear, ++ guint element_size); ++void g_array_free (GArray *array, ++ gboolean free_segment); ++GArray* g_array_append_vals (GArray *array, ++ gconstpointer data, ++ guint len); ++GArray* g_array_prepend_vals (GArray *array, ++ gconstpointer data, ++ guint len); ++GArray* g_array_insert_vals (GArray *array, ++ guint index, ++ gconstpointer data, ++ guint len); ++GArray* g_array_set_size (GArray *array, ++ guint length); ++GArray* g_array_remove_index (GArray *array, ++ guint index); ++GArray* g_array_remove_index_fast (GArray *array, ++ guint index); ++ ++/* Resizable pointer array. This interface is much less complicated ++ * than the above. Add appends appends a pointer. Remove fills any ++ * cleared spot and shortens the array. remove_fast will again distort ++ * order. ++ */ ++#define g_ptr_array_index(array,index) (array->pdata)[index] ++GPtrArray* g_ptr_array_new (void); ++void g_ptr_array_free (GPtrArray *array, ++ gboolean free_seg); ++void g_ptr_array_set_size (GPtrArray *array, ++ gint length); ++gpointer g_ptr_array_remove_index (GPtrArray *array, ++ guint index); ++gpointer g_ptr_array_remove_index_fast (GPtrArray *array, ++ guint index); ++gboolean g_ptr_array_remove (GPtrArray *array, ++ gpointer data); ++gboolean g_ptr_array_remove_fast (GPtrArray *array, ++ gpointer data); ++void g_ptr_array_add (GPtrArray *array, ++ gpointer data); ++ ++/* Hash Functions ++ */ ++gint g_str_equal (gconstpointer v, ++ gconstpointer v2); ++guint g_str_hash (gconstpointer v); ++ ++gint g_int_equal (gconstpointer v, ++ gconstpointer v2); ++guint g_int_hash (gconstpointer v); ++ ++/* This "hash" function will just return the key's adress as an ++ * unsigned integer. Useful for hashing on plain adresses or ++ * simple integer values. ++ * passing NULL into g_hash_table_new() as GHashFunc has the ++ * same effect as passing g_direct_hash(). ++ */ ++guint g_direct_hash (gconstpointer v); ++gint g_direct_equal (gconstpointer v, ++ gconstpointer v2); ++ ++ ++ ++/* Prime numbers. ++ */ ++ ++/* This function returns prime numbers spaced by approximately 1.5-2.0 ++ * and is for use in resizing data structures which prefer ++ * prime-valued sizes. The closest spaced prime function returns the ++ * next largest prime, or the highest it knows about which is about ++ * MAXINT/4. ++ */ ++guint g_spaced_primes_closest (guint num); ++ ++ ++ ++#ifndef __KORBIT__ ++/* GLib Thread support ++ */ ++typedef struct _GMutex GMutex; ++typedef struct _GCond GCond; ++typedef struct _GPrivate GPrivate; ++typedef struct _GStaticPrivate GStaticPrivate; ++typedef struct _GThreadFunctions GThreadFunctions; ++struct _GThreadFunctions ++{ ++ GMutex* (*mutex_new) (void); ++ void (*mutex_lock) (GMutex *mutex); ++ gboolean (*mutex_trylock) (GMutex *mutex); ++ void (*mutex_unlock) (GMutex *mutex); ++ void (*mutex_free) (GMutex *mutex); ++ GCond* (*cond_new) (void); ++ void (*cond_signal) (GCond *cond); ++ void (*cond_broadcast) (GCond *cond); ++ void (*cond_wait) (GCond *cond, ++ GMutex *mutex); ++ gboolean (*cond_timed_wait) (GCond *cond, ++ GMutex *mutex, ++ GTimeVal *end_time); ++ void (*cond_free) (GCond *cond); ++ GPrivate* (*private_new) (GDestroyNotify destructor); ++ gpointer (*private_get) (GPrivate *private_key); ++ void (*private_set) (GPrivate *private_key, ++ gpointer data); ++}; ++ ++GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use; ++GUTILS_C_VAR gboolean g_thread_use_default_impl; ++GUTILS_C_VAR gboolean g_threads_got_initialized; ++ ++/* initializes the mutex/cond/private implementation for glib, might ++ * only be called once, and must not be called directly or indirectly ++ * from another glib-function, e.g. as a callback. ++ */ ++void g_thread_init (GThreadFunctions *vtable); ++ ++/* internal function for fallback static mutex implementation */ ++GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex); ++ ++/* shorthands for conditional and unconditional function calls */ ++#define G_THREAD_UF(name, arglist) \ ++ (*g_thread_functions_for_glib_use . name) arglist ++#define G_THREAD_CF(name, fail, arg) \ ++ (g_thread_supported () ? G_THREAD_UF (name, arg) : (fail)) ++/* keep in mind, all those mutexes and static mutexes are not ++ * recursive in general, don't rely on that ++ */ ++#define g_thread_supported() (g_threads_got_initialized) ++#define g_mutex_new() G_THREAD_UF (mutex_new, ()) ++#define g_mutex_lock(mutex) G_THREAD_CF (mutex_lock, (void)0, (mutex)) ++#define g_mutex_trylock(mutex) G_THREAD_CF (mutex_trylock, TRUE, (mutex)) ++#define g_mutex_unlock(mutex) G_THREAD_CF (mutex_unlock, (void)0, (mutex)) ++#define g_mutex_free(mutex) G_THREAD_CF (mutex_free, (void)0, (mutex)) ++#define g_cond_new() G_THREAD_UF (cond_new, ()) ++#define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond)) ++#define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond)) ++#define g_cond_wait(cond, mutex) G_THREAD_CF (cond_wait, (void)0, (cond, \ ++ mutex)) ++#define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond)) ++#define g_cond_timed_wait(cond, mutex, abs_time) G_THREAD_CF (cond_timed_wait, \ ++ TRUE, \ ++ (cond, mutex, \ ++ abs_time)) ++#define g_private_new(destructor) G_THREAD_UF (private_new, (destructor)) ++#define g_private_get(private_key) G_THREAD_CF (private_get, \ ++ ((gpointer)private_key), \ ++ (private_key)) ++#define g_private_set(private_key, value) G_THREAD_CF (private_set, \ ++ (void) (private_key = \ ++ (GPrivate*) (value)), \ ++ (private_key, value)) ++/* GStaticMutexes can be statically initialized with the value ++ * G_STATIC_MUTEX_INIT, and then they can directly be used, that is ++ * much easier, than having to explicitly allocate the mutex before ++ * use ++ */ ++#define g_static_mutex_lock(mutex) \ ++ g_mutex_lock (g_static_mutex_get_mutex (mutex)) ++#define g_static_mutex_trylock(mutex) \ ++ g_mutex_trylock (g_static_mutex_get_mutex (mutex)) ++#define g_static_mutex_unlock(mutex) \ ++ g_mutex_unlock (g_static_mutex_get_mutex (mutex)) ++struct _GStaticPrivate ++{ ++ guint index; ++}; ++#define G_STATIC_PRIVATE_INIT { 0 } ++gpointer g_static_private_get (GStaticPrivate *private_key); ++void g_static_private_set (GStaticPrivate *private_key, ++ gpointer data, ++ GDestroyNotify notify); ++#endif /* __KORBIT__ */ ++ ++/* these are some convenience macros that expand to nothing if GLib ++ * was configured with --disable-threads. for using StaticMutexes, ++ * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name) ++ * if you need to export the mutex. With G_LOCK_EXTERN (name) you can ++ * declare such an globally defined lock. name is a unique identifier ++ * for the protected varibale or code portion. locking, testing and ++ * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and ++ * G_TRYLOCK() respectively. ++ */ ++#ifdef __KORBIT__ ++#undef G_THREADS_ENABLED ++#endif ++ ++extern void glib_dummy_decl (void); ++#define G_LOCK_NAME(name) (g__ ## name ## _lock) ++#ifdef G_THREADS_ENABLED ++# define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name) ++# define G_LOCK_DEFINE(name) \ ++ GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT ++# define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name) ++ ++# define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name)) ++# define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name)) ++# define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name)) ++#else /* !G_THREADS_ENABLED */ ++# define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void) ++# define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void) ++# define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void) ++# define G_LOCK(name) ++# define G_UNLOCK(name) ++# define G_TRYLOCK(name) (FALSE) ++#endif /* !G_THREADS_ENABLED */ ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++ ++#endif /* __G_LIB_H__ */ +diff -urN linux-2.4.1/net/korbit/kglib/glibconfig.h linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h +--- linux-2.4.1/net/korbit/kglib/glibconfig.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/glibconfig.h Thu Feb 1 11:46:56 2001 +@@ -0,0 +1,131 @@ ++/* glibconfig.h ++ * ++ * This is a generated file. Please modify `configure.in' ++ */ ++ ++#ifndef GLIBCONFIG_H ++#define GLIBCONFIG_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#include <limits.h> ++/*#include <float.h>*/ ++#define GLIB_HAVE_SYS_POLL_H ++ ++#define G_MINFLOAT FLT_MIN ++#define G_MAXFLOAT FLT_MAX ++#define G_MINDOUBLE DBL_MIN ++#define G_MAXDOUBLE DBL_MAX ++#define G_MINSHORT SHRT_MIN ++#define G_MAXSHORT SHRT_MAX ++#define G_MININT INT_MIN ++#define G_MAXINT INT_MAX ++#define G_MINLONG LONG_MIN ++#define G_MAXLONG LONG_MAX ++ ++typedef signed char gint8; ++typedef unsigned char guint8; ++typedef signed short gint16; ++typedef unsigned short guint16; ++typedef signed int gint32; ++typedef unsigned int guint32; ++ ++#if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) ++# define G_GNUC_EXTENSION __extension__ ++#else ++# define G_GNUC_EXTENSION ++#endif ++ ++#define G_HAVE_GINT64 1 ++ ++G_GNUC_EXTENSION typedef signed long long gint64; ++G_GNUC_EXTENSION typedef unsigned long long guint64; ++ ++#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL)) ++ ++#define GPOINTER_TO_INT(p) ((gint) (p)) ++#define GPOINTER_TO_UINT(p) ((guint) (p)) ++ ++#define GINT_TO_POINTER(i) ((gpointer) (i)) ++#define GUINT_TO_POINTER(u) ((gpointer) (u)) ++ ++#ifdef NeXT /* @#%@! NeXTStep */ ++# define g_ATEXIT(proc) (!atexit (proc)) ++#else ++# define g_ATEXIT(proc) (atexit (proc)) ++#endif ++ ++#define g_memmove(d,s,n) G_STMT_START { memmove ((d), (s), (n)); } G_STMT_END ++ ++#define GLIB_MAJOR_VERSION 1 ++#define GLIB_MINOR_VERSION 2 ++#define GLIB_MICRO_VERSION 8 ++ ++ ++#define G_VA_COPY __va_copy ++ ++#ifdef __cplusplus ++#define G_HAVE_INLINE 1 ++#else /* !__cplusplus */ ++#define G_HAVE_INLINE 1 ++#define G_HAVE___INLINE 1 ++#define G_HAVE___INLINE__ 1 ++#endif /* !__cplusplus */ ++ ++#define G_THREADS_ENABLED ++#define G_THREADS_IMPL_POSIX ++typedef struct _GStaticMutex GStaticMutex; ++struct _GStaticMutex ++{ ++ struct _GMutex *runtime_mutex; ++ union { ++ char pad[24]; ++ double dummy_double; ++ void *dummy_pointer; ++ long dummy_long; ++ } aligned_pad_u; ++}; ++#define G_STATIC_MUTEX_INIT { NULL, { { 0,0,0,0,0,0,77,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } } ++#define g_static_mutex_get_mutex(mutex) (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex))) ++ ++#define GINT16_TO_BE(val) ((gint16) (val)) ++#define GUINT16_TO_BE(val) ((guint16) (val)) ++#define GINT16_TO_LE(val) ((gint16) GUINT16_SWAP_LE_BE (val)) ++#define GUINT16_TO_LE(val) (GUINT16_SWAP_LE_BE (val)) ++#define GINT32_TO_BE(val) ((gint32) (val)) ++#define GUINT32_TO_BE(val) ((guint32) (val)) ++#define GINT32_TO_LE(val) ((gint32) GUINT32_SWAP_LE_BE (val)) ++#define GUINT32_TO_LE(val) (GUINT32_SWAP_LE_BE (val)) ++#define GINT64_TO_BE(val) ((gint64) (val)) ++#define GUINT64_TO_BE(val) ((guint64) (val)) ++#define GINT64_TO_LE(val) ((gint64) GUINT64_SWAP_LE_BE (val)) ++#define GUINT64_TO_LE(val) (GUINT64_SWAP_LE_BE (val)) ++#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val)) ++#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val)) ++#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val)) ++#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val)) ++#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val)) ++#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val)) ++#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val)) ++#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val)) ++#define G_BYTE_ORDER G_LITTLE_ENDIAN ++ ++#define GLIB_SYSDEF_POLLIN =1 ++#define GLIB_SYSDEF_POLLOUT =4 ++#define GLIB_SYSDEF_POLLPRI =2 ++#define GLIB_SYSDEF_POLLERR =8 ++#define GLIB_SYSDEF_POLLHUP =16 ++#define GLIB_SYSDEF_POLLNVAL =32 ++ ++ ++#define G_HAVE_WCHAR_H 1 ++#define G_HAVE_WCTYPE_H 1 ++ ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* GLIBCONFIG_H */ +diff -urN linux-2.4.1/net/korbit/kglib/glist.c linux-2.4.1-korbit/net/korbit/kglib/glist.c +--- linux-2.4.1/net/korbit/kglib/glist.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/glist.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,666 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include "glib.h" ++ ++ ++struct _GAllocator /* from gmem.c */ ++{ ++ gchar *name; ++ guint16 n_preallocs; ++ guint is_unused : 1; ++ guint type : 4; ++ GAllocator *last; ++ GMemChunk *mem_chunk; ++ GList *free_lists; /* implementation specific */ ++}; ++ ++static GAllocator *current_allocator = NULL; ++G_LOCK_DEFINE_STATIC (current_allocator); ++ ++/* HOLDS: current_allocator_lock */ ++static void ++g_list_validate_allocator (GAllocator *allocator) ++{ ++ g_return_if_fail (allocator != NULL); ++ g_return_if_fail (allocator->is_unused == TRUE); ++ ++ if (allocator->type != G_ALLOCATOR_LIST) ++ { ++ allocator->type = G_ALLOCATOR_LIST; ++ if (allocator->mem_chunk) ++ { ++ g_mem_chunk_destroy (allocator->mem_chunk); ++ allocator->mem_chunk = NULL; ++ } ++ } ++ ++ if (!allocator->mem_chunk) ++ { ++ allocator->mem_chunk = g_mem_chunk_new (allocator->name, ++ sizeof (GList), ++ sizeof (GList) * allocator->n_preallocs, ++ G_ALLOC_ONLY); ++ allocator->free_lists = NULL; ++ } ++ ++ allocator->is_unused = FALSE; ++} ++ ++void ++g_list_push_allocator(GAllocator *allocator) ++{ ++ G_LOCK (current_allocator); ++ g_list_validate_allocator ( allocator ); ++ allocator->last = current_allocator; ++ current_allocator = allocator; ++ G_UNLOCK (current_allocator); ++} ++ ++void ++g_list_pop_allocator (void) ++{ ++ G_LOCK (current_allocator); ++ if (current_allocator) ++ { ++ GAllocator *allocator; ++ ++ allocator = current_allocator; ++ current_allocator = allocator->last; ++ allocator->last = NULL; ++ allocator->is_unused = TRUE; ++ } ++ G_UNLOCK (current_allocator); ++} ++ ++GList* ++g_list_alloc (void) ++{ ++ GList *list; ++ ++ G_LOCK (current_allocator); ++ if (!current_allocator) ++ { ++ GAllocator *allocator = g_allocator_new ("GLib default GList allocator", ++ 128); ++ g_list_validate_allocator (allocator); ++ allocator->last = NULL; ++ current_allocator = allocator; ++ } ++ if (!current_allocator->free_lists) ++ { ++ list = g_chunk_new (GList, current_allocator->mem_chunk); ++ list->data = NULL; ++ } ++ else ++ { ++ if (current_allocator->free_lists->data) ++ { ++ list = current_allocator->free_lists->data; ++ current_allocator->free_lists->data = list->next; ++ list->data = NULL; ++ } ++ else ++ { ++ list = current_allocator->free_lists; ++ current_allocator->free_lists = list->next; ++ } ++ } ++ G_UNLOCK (current_allocator); ++ list->next = NULL; ++ list->prev = NULL; ++ ++ return list; ++} ++ ++void ++g_list_free (GList *list) ++{ ++ if (list) ++ { ++ list->data = list->next; ++ G_LOCK (current_allocator); ++ list->next = current_allocator->free_lists; ++ current_allocator->free_lists = list; ++ G_UNLOCK (current_allocator); ++ } ++} ++ ++void ++g_list_free_1 (GList *list) ++{ ++ if (list) ++ { ++ list->data = NULL; ++ G_LOCK (current_allocator); ++ list->next = current_allocator->free_lists; ++ current_allocator->free_lists = list; ++ G_UNLOCK (current_allocator); ++ } ++} ++ ++GList* ++g_list_append (GList *list, ++ gpointer data) ++{ ++ GList *new_list; ++ GList *last; ++ ++ new_list = g_list_alloc (); ++ new_list->data = data; ++ ++ if (list) ++ { ++ last = g_list_last (list); ++ /* g_assert (last != NULL); */ ++ last->next = new_list; ++ new_list->prev = last; ++ ++ return list; ++ } ++ else ++ return new_list; ++} ++ ++GList* ++g_list_prepend (GList *list, ++ gpointer data) ++{ ++ GList *new_list; ++ ++ new_list = g_list_alloc (); ++ new_list->data = data; ++ ++ if (list) ++ { ++ if (list->prev) ++ { ++ list->prev->next = new_list; ++ new_list->prev = list->prev; ++ } ++ list->prev = new_list; ++ new_list->next = list; ++ } ++ ++ return new_list; ++} ++ ++GList* ++g_list_insert (GList *list, ++ gpointer data, ++ gint position) ++{ ++ GList *new_list; ++ GList *tmp_list; ++ ++ if (position < 0) ++ return g_list_append (list, data); ++ else if (position == 0) ++ return g_list_prepend (list, data); ++ ++ tmp_list = g_list_nth (list, position); ++ if (!tmp_list) ++ return g_list_append (list, data); ++ ++ new_list = g_list_alloc (); ++ new_list->data = data; ++ ++ if (tmp_list->prev) ++ { ++ tmp_list->prev->next = new_list; ++ new_list->prev = tmp_list->prev; ++ } ++ new_list->next = tmp_list; ++ tmp_list->prev = new_list; ++ ++ if (tmp_list == list) ++ return new_list; ++ else ++ return list; ++} ++ ++GList * ++g_list_concat (GList *list1, GList *list2) ++{ ++ GList *tmp_list; ++ ++ if (list2) ++ { ++ tmp_list = g_list_last (list1); ++ if (tmp_list) ++ tmp_list->next = list2; ++ else ++ list1 = list2; ++ list2->prev = tmp_list; ++ } ++ ++ return list1; ++} ++ ++GList* ++g_list_remove (GList *list, ++ gpointer data) ++{ ++ GList *tmp; ++ ++ tmp = list; ++ while (tmp) ++ { ++ if (tmp->data != data) ++ tmp = tmp->next; ++ else ++ { ++ if (tmp->prev) ++ tmp->prev->next = tmp->next; ++ if (tmp->next) ++ tmp->next->prev = tmp->prev; ++ ++ if (list == tmp) ++ list = list->next; ++ ++ g_list_free_1 (tmp); ++ ++ break; ++ } ++ } ++ return list; ++} ++ ++GList* ++g_list_remove_link (GList *list, ++ GList *link) ++{ ++ if (link) ++ { ++ if (link->prev) ++ link->prev->next = link->next; ++ if (link->next) ++ link->next->prev = link->prev; ++ ++ if (link == list) ++ list = list->next; ++ ++ link->next = NULL; ++ link->prev = NULL; ++ } ++ ++ return list; ++} ++ ++GList* ++g_list_copy (GList *list) ++{ ++ GList *new_list = NULL; ++ ++ if (list) ++ { ++ GList *last; ++ ++ new_list = g_list_alloc (); ++ new_list->data = list->data; ++ last = new_list; ++ list = list->next; ++ while (list) ++ { ++ last->next = g_list_alloc (); ++ last->next->prev = last; ++ last = last->next; ++ last->data = list->data; ++ list = list->next; ++ } ++ } ++ ++ return new_list; ++} ++ ++GList* ++g_list_reverse (GList *list) ++{ ++ GList *last; ++ ++ last = NULL; ++ while (list) ++ { ++ last = list; ++ list = last->next; ++ last->next = last->prev; ++ last->prev = list; ++ } ++ ++ return last; ++} ++ ++GList* ++g_list_nth (GList *list, ++ guint n) ++{ ++ while ((n-- > 0) && list) ++ list = list->next; ++ ++ return list; ++} ++ ++gpointer ++g_list_nth_data (GList *list, ++ guint n) ++{ ++ while ((n-- > 0) && list) ++ list = list->next; ++ ++ return list ? list->data : NULL; ++} ++ ++GList* ++g_list_find (GList *list, ++ gpointer data) ++{ ++ while (list) ++ { ++ if (list->data == data) ++ break; ++ list = list->next; ++ } ++ ++ return list; ++} ++ ++GList* ++g_list_find_custom (GList *list, ++ gpointer data, ++ GCompareFunc func) ++{ ++ g_return_val_if_fail (func != NULL, list); ++ ++ while (list) ++ { ++ if (! func (list->data, data)) ++ return list; ++ list = list->next; ++ } ++ ++ return NULL; ++} ++ ++ ++gint ++g_list_position (GList *list, ++ GList *link) ++{ ++ gint i; ++ ++ i = 0; ++ while (list) ++ { ++ if (list == link) ++ return i; ++ i++; ++ list = list->next; ++ } ++ ++ return -1; ++} ++ ++gint ++g_list_index (GList *list, ++ gpointer data) ++{ ++ gint i; ++ ++ i = 0; ++ while (list) ++ { ++ if (list->data == data) ++ return i; ++ i++; ++ list = list->next; ++ } ++ ++ return -1; ++} ++ ++GList* ++g_list_last (GList *list) ++{ ++ if (list) ++ { ++ while (list->next) ++ list = list->next; ++ } ++ ++ return list; ++} ++ ++GList* ++g_list_first (GList *list) ++{ ++ if (list) ++ { ++ while (list->prev) ++ list = list->prev; ++ } ++ ++ return list; ++} ++ ++guint ++g_list_length (GList *list) ++{ ++ guint length; ++ ++ length = 0; ++ while (list) ++ { ++ length++; ++ list = list->next; ++ } ++ ++ return length; ++} ++ ++void ++g_list_foreach (GList *list, ++ GFunc func, ++ gpointer user_data) ++{ ++ while (list) ++ { ++ (*func) (list->data, user_data); ++ list = list->next; ++ } ++} ++ ++ ++GList* ++g_list_insert_sorted (GList *list, ++ gpointer data, ++ GCompareFunc func) ++{ ++ GList *tmp_list = list; ++ GList *new_list; ++ gint cmp; ++ ++ g_return_val_if_fail (func != NULL, list); ++ ++ if (!list) ++ { ++ new_list = g_list_alloc(); ++ new_list->data = data; ++ return new_list; ++ } ++ ++ cmp = (*func) (data, tmp_list->data); ++ ++ while ((tmp_list->next) && (cmp > 0)) ++ { ++ tmp_list = tmp_list->next; ++ cmp = (*func) (data, tmp_list->data); ++ } ++ ++ new_list = g_list_alloc(); ++ new_list->data = data; ++ ++ if ((!tmp_list->next) && (cmp > 0)) ++ { ++ tmp_list->next = new_list; ++ new_list->prev = tmp_list; ++ return list; ++ } ++ ++ if (tmp_list->prev) ++ { ++ tmp_list->prev->next = new_list; ++ new_list->prev = tmp_list->prev; ++ } ++ new_list->next = tmp_list; ++ tmp_list->prev = new_list; ++ ++ if (tmp_list == list) ++ return new_list; ++ else ++ return list; ++} ++ ++static GList * ++g_list_sort_merge (GList *l1, ++ GList *l2, ++ GCompareFunc compare_func) ++{ ++ GList list, *l, *lprev; ++ ++ l = &list; ++ lprev = NULL; ++ ++ while (l1 && l2) ++ { ++ if (compare_func (l1->data, l2->data) < 0) ++ { ++ l->next = l1; ++ l = l->next; ++ l->prev = lprev; ++ lprev = l; ++ l1 = l1->next; ++ } ++ else ++ { ++ l->next = l2; ++ l = l->next; ++ l->prev = lprev; ++ lprev = l; ++ l2 = l2->next; ++ } ++ } ++ l->next = l1 ? l1 : l2; ++ l->next->prev = l; ++ ++ return list.next; ++} ++ ++GList* ++g_list_sort (GList *list, ++ GCompareFunc compare_func) ++{ ++ GList *l1, *l2; ++ ++ if (!list) ++ return NULL; ++ if (!list->next) ++ return list; ++ ++ l1 = list; ++ l2 = list->next; ++ ++ while ((l2 = l2->next) != NULL) ++ { ++ if ((l2 = l2->next) == NULL) ++ break; ++ l1 = l1->next; ++ } ++ l2 = l1->next; ++ l1->next = NULL; ++ ++ return g_list_sort_merge (g_list_sort (list, compare_func), ++ g_list_sort (l2, compare_func), ++ compare_func); ++} ++ ++GList* ++g_list_sort2 (GList *list, ++ GCompareFunc compare_func) ++{ ++ GSList *runs = NULL; ++ GList *tmp; ++ ++ /* Degenerate case. */ ++ if (!list) return NULL; ++ ++ /* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */ ++ for (tmp = list; tmp; ) ++ { ++ GList *tmp2; ++ for (tmp2 = tmp; ++ tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0; ++ tmp2 = tmp2->next) ++ /* Nothing */; ++ runs = g_slist_append (runs, tmp); ++ tmp = tmp2->next; ++ tmp2->next = NULL; ++ } ++ /* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */ ++ ++ while (runs->next) ++ { ++ /* We have more than one run. Merge pairwise. */ ++ GSList *dst, *src, *dstprev = NULL; ++ dst = src = runs; ++ while (src && src->next) ++ { ++ dst->data = g_list_sort_merge (src->data, ++ src->next->data, ++ compare_func); ++ dstprev = dst; ++ dst = dst->next; ++ src = src->next->next; ++ } ++ ++ /* If number of runs was odd, just keep the last. */ ++ if (src) ++ { ++ dst->data = src->data; ++ dstprev = dst; ++ dst = dst->next; ++ } ++ ++ dstprev->next = NULL; ++ g_slist_free (dst); ++ } ++ ++ /* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */ ++ /* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */ ++ ++ list = runs->data; ++ g_slist_free (runs); ++ return list; ++} +diff -urN linux-2.4.1/net/korbit/kglib/gmem.c linux-2.4.1-korbit/net/korbit/kglib/gmem.c +--- linux-2.4.1/net/korbit/kglib/gmem.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gmem.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,767 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ * ++ * Mutilated on 10/22/00 by Fredrik and Chris ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <stdlib.h> ++#include <string.h> ++#include "glib.h" ++ ++#define MEM_PROFILE_TABLE_SIZE 8192 ++#define ENTER_MEM_CHUNK_ROUTINE() ++#define LEAVE_MEM_CHUNK_ROUTINE() ++ ++/* ++ * This library can check for some attempts to do illegal things to ++ * memory (ENABLE_MEM_CHECK), and can do profiling ++ * (ENABLE_MEM_PROFILE). Both features are implemented by storing ++ * words before the start of the memory chunk. ++ * ++ * The first, at offset -2*SIZEOF_LONG, is used only if ++ * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been ++ * allocated and 1 when it has been freed. The second, at offset ++ * -SIZEOF_LONG, is used if either flag is set and stores the size of ++ * the block. ++ * ++ * The MEM_CHECK flag is checked when memory is realloc'd and free'd, ++ * and it can be explicitly checked before using a block by calling ++ * g_mem_check(). ++ */ ++ ++#define MEM_AREA_SIZE 4L ++ ++#define MEM_ALIGN sizeof(long) ++ ++ ++typedef struct _GFreeAtom GFreeAtom; ++typedef struct _GMemArea GMemArea; ++typedef struct _GRealMemChunk GRealMemChunk; ++ ++struct _GFreeAtom ++{ ++ GFreeAtom *next; ++}; ++ ++struct _GMemArea ++{ ++ GMemArea *next; /* the next mem area */ ++ GMemArea *prev; /* the previous mem area */ ++ gulong index; /* the current index into the "mem" array */ ++ gulong free; /* the number of free bytes in this mem area */ ++ gulong allocated; /* the number of atoms allocated from this area */ ++ gulong mark; /* is this mem area marked for deletion */ ++ gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated ++ * the actual size of this array is determined by ++ * the mem chunk "area_size". ANSI says that it ++ * must be declared to be the maximum size it ++ * can possibly be (even though the actual size ++ * may be less). ++ */ ++}; ++ ++struct _GRealMemChunk ++{ ++ gchar *name; /* name of this MemChunk...used for debugging output */ ++ gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */ ++ gint num_mem_areas; /* the number of memory areas */ ++ gint num_marked_areas; /* the number of areas marked for deletion */ ++ guint atom_size; /* the size of an atom */ ++ gulong area_size; /* the size of a memory area */ ++ GMemArea *mem_area; /* the current memory area */ ++ GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */ ++ GMemArea *free_mem_area; /* the free area...which is about to be destroyed */ ++ GFreeAtom *free_atoms; /* the free atoms list */ ++ GTree *mem_tree; /* tree of mem areas sorted by memory address */ ++ GRealMemChunk *next; /* pointer to the next chunk */ ++ GRealMemChunk *prev; /* pointer to the previous chunk */ ++}; ++ ++ ++static gulong g_mem_chunk_compute_size (gulong size, ++ gulong min_size); ++static gint g_mem_chunk_area_compare (GMemArea *a, ++ GMemArea *b); ++static gint g_mem_chunk_area_search (GMemArea *a, ++ gchar *addr); ++ ++ ++/* here we can't use StaticMutexes, as they depend upon a working ++ * g_malloc, the same holds true for StaticPrivate */ ++#ifndef __KORBIT__ ++static GMutex* mem_chunks_lock = NULL; ++#endif /* !__KORBIT__ */ ++static GRealMemChunk *mem_chunks = NULL; ++ ++ ++gpointer ++g_malloc (gulong size) ++{ ++ gpointer p; ++ ++ if (size == 0) ++ return NULL; ++ ++ p = (gpointer) malloc (size); ++ if (!p) ++ g_error ("could not allocate %ld bytes", size); ++ ++ return p; ++} ++ ++gpointer ++g_malloc0 (gulong size) ++{ ++ gpointer p; ++ ++ if (size == 0) ++ return NULL; ++ ++ p = (gpointer) calloc (size, 1); ++ if (!p) ++ g_error ("could not allocate %ld bytes", size); ++ ++ return p; ++} ++ ++gpointer ++g_realloc (gpointer mem, ++ gulong size) ++{ ++ gpointer p; ++ ++ if (size == 0) ++ { ++ g_free (mem); ++ ++ return NULL; ++ } ++ ++ if (!mem) ++ { ++#ifdef REALLOC_0_WORKS ++ p = (gpointer) realloc (NULL, size); ++#else /* !REALLOC_0_WORKS */ ++ p = (gpointer) malloc (size); ++#endif /* !REALLOC_0_WORKS */ ++ } ++ else ++ { ++ p = (gpointer) realloc (mem, size); ++ } ++ ++ if (!p) ++ g_error ("could not reallocate %lu bytes", (gulong) size); ++ ++ return p; ++} ++ ++void ++g_free (gpointer mem) ++{ ++ if (mem) ++ { ++ free (mem); ++ } ++} ++ ++ ++void ++g_mem_profile (void) ++{ ++} ++ ++void ++g_mem_check (gpointer mem) ++{ ++} ++ ++GMemChunk* ++g_mem_chunk_new (gchar *name, ++ gint atom_size, ++ gulong area_size, ++ gint type) ++{ ++ GRealMemChunk *mem_chunk; ++ gulong rarea_size; ++ ++ g_return_val_if_fail (atom_size > 0, NULL); ++ g_return_val_if_fail (area_size >= atom_size, NULL); ++ ++ ENTER_MEM_CHUNK_ROUTINE(); ++ ++ area_size = (area_size + atom_size - 1) / atom_size; ++ area_size *= atom_size; ++ ++ mem_chunk = g_new (struct _GRealMemChunk, 1); ++ mem_chunk->name = name; ++ mem_chunk->type = type; ++ mem_chunk->num_mem_areas = 0; ++ mem_chunk->num_marked_areas = 0; ++ mem_chunk->mem_area = NULL; ++ mem_chunk->free_mem_area = NULL; ++ mem_chunk->free_atoms = NULL; ++ mem_chunk->mem_tree = NULL; ++ mem_chunk->mem_areas = NULL; ++ mem_chunk->atom_size = atom_size; ++ ++ if (mem_chunk->type == G_ALLOC_AND_FREE) ++ mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); ++ ++ if (mem_chunk->atom_size % MEM_ALIGN) ++ mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); ++ ++ rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE; ++ rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE); ++ mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE); ++ ++#ifndef __KORBIT__ ++ g_mutex_lock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ mem_chunk->next = mem_chunks; ++ mem_chunk->prev = NULL; ++ if (mem_chunks) ++ mem_chunks->prev = mem_chunk; ++ mem_chunks = mem_chunk; ++#ifndef __KORBIT__ ++ g_mutex_unlock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ ++ LEAVE_MEM_CHUNK_ROUTINE(); ++ ++ return ((GMemChunk*) mem_chunk); ++} ++ ++void ++g_mem_chunk_destroy (GMemChunk *mem_chunk) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *mem_areas; ++ GMemArea *temp_area; ++ ++ g_return_if_fail (mem_chunk != NULL); ++ ++ ENTER_MEM_CHUNK_ROUTINE(); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ mem_areas = rmem_chunk->mem_areas; ++ while (mem_areas) ++ { ++ temp_area = mem_areas; ++ mem_areas = mem_areas->next; ++ g_free (temp_area); ++ } ++ ++ if (rmem_chunk->next) ++ rmem_chunk->next->prev = rmem_chunk->prev; ++ if (rmem_chunk->prev) ++ rmem_chunk->prev->next = rmem_chunk->next; ++ ++#ifndef __KORBIT__ ++ g_mutex_lock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ if (rmem_chunk == mem_chunks) ++ mem_chunks = mem_chunks->next; ++#ifndef __KORBIT__ ++ g_mutex_unlock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ g_tree_destroy (rmem_chunk->mem_tree); ++ ++ g_free (rmem_chunk); ++ ++ LEAVE_MEM_CHUNK_ROUTINE(); ++} ++ ++gpointer ++g_mem_chunk_alloc (GMemChunk *mem_chunk) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *temp_area; ++ gpointer mem; ++ ++ ENTER_MEM_CHUNK_ROUTINE(); ++ ++ g_return_val_if_fail (mem_chunk != NULL, NULL); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ while (rmem_chunk->free_atoms) ++ { ++ /* Get the first piece of memory on the "free_atoms" list. ++ * We can go ahead and destroy the list node we used to keep ++ * track of it with and to update the "free_atoms" list to ++ * point to its next element. ++ */ ++ mem = rmem_chunk->free_atoms; ++ rmem_chunk->free_atoms = rmem_chunk->free_atoms->next; ++ ++ /* Determine which area this piece of memory is allocated from */ ++ temp_area = g_tree_search (rmem_chunk->mem_tree, ++ (GSearchFunc) g_mem_chunk_area_search, ++ mem); ++ ++ /* If the area has been marked, then it is being destroyed. ++ * (ie marked to be destroyed). ++ * We check to see if all of the segments on the free list that ++ * reference this area have been removed. This occurs when ++ * the ammount of free memory is less than the allocatable size. ++ * If the chunk should be freed, then we place it in the "free_mem_area". ++ * This is so we make sure not to free the mem area here and then ++ * allocate it again a few lines down. ++ * If we don't allocate a chunk a few lines down then the "free_mem_area" ++ * will be freed. ++ * If there is already a "free_mem_area" then we'll just free this mem area. ++ */ ++ if (temp_area->mark) ++ { ++ /* Update the "free" memory available in that area */ ++ temp_area->free += rmem_chunk->atom_size; ++ ++ if (temp_area->free == rmem_chunk->area_size) ++ { ++ if (temp_area == rmem_chunk->mem_area) ++ rmem_chunk->mem_area = NULL; ++ ++ if (rmem_chunk->free_mem_area) ++ { ++ rmem_chunk->num_mem_areas -= 1; ++ ++ if (temp_area->next) ++ temp_area->next->prev = temp_area->prev; ++ if (temp_area->prev) ++ temp_area->prev->next = temp_area->next; ++ if (temp_area == rmem_chunk->mem_areas) ++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; ++ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ g_tree_remove (rmem_chunk->mem_tree, temp_area); ++ g_free (temp_area); ++ } ++ else ++ rmem_chunk->free_mem_area = temp_area; ++ ++ rmem_chunk->num_marked_areas -= 1; ++ } ++ } ++ else ++ { ++ /* Update the number of allocated atoms count. ++ */ ++ temp_area->allocated += 1; ++ ++ /* The area wasn't marked...return the memory ++ */ ++ goto outa_here; ++ } ++ } ++ ++ /* If there isn't a current mem area or the current mem area is out of space ++ * then allocate a new mem area. We'll first check and see if we can use ++ * the "free_mem_area". Otherwise we'll just malloc the mem area. ++ */ ++ if ((!rmem_chunk->mem_area) || ++ ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size)) ++ { ++ if (rmem_chunk->free_mem_area) ++ { ++ rmem_chunk->mem_area = rmem_chunk->free_mem_area; ++ rmem_chunk->free_mem_area = NULL; ++ } ++ else ++ { ++ rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) - ++ MEM_AREA_SIZE + ++ rmem_chunk->area_size); ++ ++ rmem_chunk->num_mem_areas += 1; ++ rmem_chunk->mem_area->next = rmem_chunk->mem_areas; ++ rmem_chunk->mem_area->prev = NULL; ++ ++ if (rmem_chunk->mem_areas) ++ rmem_chunk->mem_areas->prev = rmem_chunk->mem_area; ++ rmem_chunk->mem_areas = rmem_chunk->mem_area; ++ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area); ++ } ++ ++ rmem_chunk->mem_area->index = 0; ++ rmem_chunk->mem_area->free = rmem_chunk->area_size; ++ rmem_chunk->mem_area->allocated = 0; ++ rmem_chunk->mem_area->mark = 0; ++ } ++ ++ /* Get the memory and modify the state variables appropriately. ++ */ ++ mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index]; ++ rmem_chunk->mem_area->index += rmem_chunk->atom_size; ++ rmem_chunk->mem_area->free -= rmem_chunk->atom_size; ++ rmem_chunk->mem_area->allocated += 1; ++ ++outa_here: ++ ++ LEAVE_MEM_CHUNK_ROUTINE(); ++ ++ return mem; ++} ++ ++gpointer ++g_mem_chunk_alloc0 (GMemChunk *mem_chunk) ++{ ++ gpointer mem; ++ ++ mem = g_mem_chunk_alloc (mem_chunk); ++ if (mem) ++ { ++ GRealMemChunk *rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ memset (mem, 0, rmem_chunk->atom_size); ++ } ++ ++ return mem; ++} ++ ++void ++g_mem_chunk_free (GMemChunk *mem_chunk, ++ gpointer mem) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *temp_area; ++ GFreeAtom *free_atom; ++ ++ g_return_if_fail (mem_chunk != NULL); ++ g_return_if_fail (mem != NULL); ++ ++ ENTER_MEM_CHUNK_ROUTINE(); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ /* Don't do anything if this is an ALLOC_ONLY chunk ++ */ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ { ++ /* Place the memory on the "free_atoms" list ++ */ ++ free_atom = (GFreeAtom*) mem; ++ free_atom->next = rmem_chunk->free_atoms; ++ rmem_chunk->free_atoms = free_atom; ++ ++ temp_area = g_tree_search (rmem_chunk->mem_tree, ++ (GSearchFunc) g_mem_chunk_area_search, ++ mem); ++ ++ temp_area->allocated -= 1; ++ ++ if (temp_area->allocated == 0) ++ { ++ temp_area->mark = 1; ++ rmem_chunk->num_marked_areas += 1; ++ } ++ } ++ ++ LEAVE_MEM_CHUNK_ROUTINE(); ++} ++ ++/* This doesn't free the free_area if there is one */ ++void ++g_mem_chunk_clean (GMemChunk *mem_chunk) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *mem_area; ++ GFreeAtom *prev_free_atom; ++ GFreeAtom *temp_free_atom; ++ gpointer mem; ++ ++ g_return_if_fail (mem_chunk != NULL); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ { ++ prev_free_atom = NULL; ++ temp_free_atom = rmem_chunk->free_atoms; ++ ++ while (temp_free_atom) ++ { ++ mem = (gpointer) temp_free_atom; ++ ++ mem_area = g_tree_search (rmem_chunk->mem_tree, ++ (GSearchFunc) g_mem_chunk_area_search, ++ mem); ++ ++ /* If this mem area is marked for destruction then delete the ++ * area and list node and decrement the free mem. ++ */ ++ if (mem_area->mark) ++ { ++ if (prev_free_atom) ++ prev_free_atom->next = temp_free_atom->next; ++ else ++ rmem_chunk->free_atoms = temp_free_atom->next; ++ temp_free_atom = temp_free_atom->next; ++ ++ mem_area->free += rmem_chunk->atom_size; ++ if (mem_area->free == rmem_chunk->area_size) ++ { ++ rmem_chunk->num_mem_areas -= 1; ++ rmem_chunk->num_marked_areas -= 1; ++ ++ if (mem_area->next) ++ mem_area->next->prev = mem_area->prev; ++ if (mem_area->prev) ++ mem_area->prev->next = mem_area->next; ++ if (mem_area == rmem_chunk->mem_areas) ++ rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; ++ if (mem_area == rmem_chunk->mem_area) ++ rmem_chunk->mem_area = NULL; ++ ++ if (rmem_chunk->type == G_ALLOC_AND_FREE) ++ g_tree_remove (rmem_chunk->mem_tree, mem_area); ++ g_free (mem_area); ++ } ++ } ++ else ++ { ++ prev_free_atom = temp_free_atom; ++ temp_free_atom = temp_free_atom->next; ++ } ++ } ++ } ++} ++ ++void ++g_mem_chunk_reset (GMemChunk *mem_chunk) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *mem_areas; ++ GMemArea *temp_area; ++ ++ g_return_if_fail (mem_chunk != NULL); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ ++ mem_areas = rmem_chunk->mem_areas; ++ rmem_chunk->num_mem_areas = 0; ++ rmem_chunk->mem_areas = NULL; ++ rmem_chunk->mem_area = NULL; ++ ++ while (mem_areas) ++ { ++ temp_area = mem_areas; ++ mem_areas = mem_areas->next; ++ g_free (temp_area); ++ } ++ ++ rmem_chunk->free_atoms = NULL; ++ ++ if (rmem_chunk->mem_tree) ++ g_tree_destroy (rmem_chunk->mem_tree); ++ rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); ++} ++ ++void ++g_mem_chunk_print (GMemChunk *mem_chunk) ++{ ++ GRealMemChunk *rmem_chunk; ++ GMemArea *mem_areas; ++ gulong mem; ++ ++ g_return_if_fail (mem_chunk != NULL); ++ ++ rmem_chunk = (GRealMemChunk*) mem_chunk; ++ mem_areas = rmem_chunk->mem_areas; ++ mem = 0; ++ ++ while (mem_areas) ++ { ++ mem += rmem_chunk->area_size - mem_areas->free; ++ mem_areas = mem_areas->next; ++ } ++ ++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, ++ "%s: %ld bytes using %d mem areas", ++ rmem_chunk->name, mem, rmem_chunk->num_mem_areas); ++} ++ ++void ++g_mem_chunk_info (void) ++{ ++ GRealMemChunk *mem_chunk; ++ gint count; ++ ++ count = 0; ++#ifndef __KORBIT__ ++ g_mutex_lock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ mem_chunk = mem_chunks; ++ while (mem_chunk) ++ { ++ count += 1; ++ mem_chunk = mem_chunk->next; ++ } ++#ifndef __KORBIT__ ++ g_mutex_unlock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks", count); ++ ++#ifndef __KORBIT__ ++ g_mutex_lock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ mem_chunk = mem_chunks; ++#ifndef __KORBIT__ ++ g_mutex_unlock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ ++ while (mem_chunk) ++ { ++ g_mem_chunk_print ((GMemChunk*) mem_chunk); ++ mem_chunk = mem_chunk->next; ++ } ++} ++ ++void ++g_blow_chunks (void) ++{ ++ GRealMemChunk *mem_chunk; ++ ++#ifndef __KORBIT__ ++ g_mutex_lock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ mem_chunk = mem_chunks; ++#ifndef __KORBIT__ ++ g_mutex_unlock (mem_chunks_lock); ++#endif /* !__KORBIT__ */ ++ while (mem_chunk) ++ { ++ g_mem_chunk_clean ((GMemChunk*) mem_chunk); ++ mem_chunk = mem_chunk->next; ++ } ++} ++ ++ ++static gulong ++g_mem_chunk_compute_size (gulong size, ++ gulong min_size) ++{ ++ gulong power_of_2; ++ gulong lower, upper; ++ ++ power_of_2 = 16; ++ while (power_of_2 < size) ++ power_of_2 <<= 1; ++ ++ lower = power_of_2 >> 1; ++ upper = power_of_2; ++ ++ if (size - lower < upper - size && lower >= min_size) ++ return lower; ++ else ++ return upper; ++} ++ ++static gint ++g_mem_chunk_area_compare (GMemArea *a, ++ GMemArea *b) ++{ ++ if (a->mem > b->mem) ++ return 1; ++ else if (a->mem < b->mem) ++ return -1; ++ return 0; ++} ++ ++static gint ++g_mem_chunk_area_search (GMemArea *a, ++ gchar *addr) ++{ ++ if (a->mem <= addr) ++ { ++ if (addr < &a->mem[a->index]) ++ return 0; ++ return 1; ++ } ++ return -1; ++} ++ ++/* generic allocators ++ */ ++struct _GAllocator /* from gmem.c */ ++{ ++ gchar *name; ++ guint16 n_preallocs; ++ guint is_unused : 1; ++ guint type : 4; ++ GAllocator *last; ++ GMemChunk *mem_chunk; ++ gpointer dummy; /* implementation specific */ ++}; ++ ++GAllocator* ++g_allocator_new (const gchar *name, ++ guint n_preallocs) ++{ ++ GAllocator *allocator; ++ ++ g_return_val_if_fail (name != NULL, NULL); ++ ++ allocator = g_new0 (GAllocator, 1); ++ allocator->name = g_strdup (name); ++ allocator->n_preallocs = CLAMP (n_preallocs, 1, 65535); ++ allocator->is_unused = TRUE; ++ allocator->type = 0; ++ allocator->last = NULL; ++ allocator->mem_chunk = NULL; ++ allocator->dummy = NULL; ++ ++ return allocator; ++} ++ ++void ++g_allocator_free (GAllocator *allocator) ++{ ++ g_return_if_fail (allocator != NULL); ++ g_return_if_fail (allocator->is_unused == TRUE); ++ ++ g_free (allocator->name); ++ if (allocator->mem_chunk) ++ g_mem_chunk_destroy (allocator->mem_chunk); ++ ++ g_free (allocator); ++} ++ ++void ++g_mem_init (void) ++{ ++#ifndef __KORBIT__ ++ mem_chunks_lock = g_mutex_new(); ++#endif /* !__KORBIT__ */ ++} +diff -urN linux-2.4.1/net/korbit/kglib/gprimes.c linux-2.4.1-korbit/net/korbit/kglib/gprimes.c +--- linux-2.4.1/net/korbit/kglib/gprimes.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gprimes.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,79 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include "glib.h" ++ ++static const guint g_primes[] = ++{ ++ 11, ++ 19, ++ 37, ++ 73, ++ 109, ++ 163, ++ 251, ++ 367, ++ 557, ++ 823, ++ 1237, ++ 1861, ++ 2777, ++ 4177, ++ 6247, ++ 9371, ++ 14057, ++ 21089, ++ 31627, ++ 47431, ++ 71143, ++ 106721, ++ 160073, ++ 240101, ++ 360163, ++ 540217, ++ 810343, ++ 1215497, ++ 1823231, ++ 2734867, ++ 4102283, ++ 6153409, ++ 9230113, ++ 13845163, ++}; ++ ++static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]); ++ ++guint ++g_spaced_primes_closest (guint num) ++{ ++ gint i; ++ ++ for (i = 0; i < g_nprimes; i++) ++ if (g_primes[i] > num) ++ return g_primes[i]; ++ ++ return g_primes[g_nprimes - 1]; ++} +diff -urN linux-2.4.1/net/korbit/kglib/gslist.c linux-2.4.1-korbit/net/korbit/kglib/gslist.c +--- linux-2.4.1/net/korbit/kglib/gslist.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gslist.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,591 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include "glib.h" ++ ++ ++struct _GAllocator /* from gmem.c */ ++{ ++ gchar *name; ++ guint16 n_preallocs; ++ guint is_unused : 1; ++ guint type : 4; ++ GAllocator *last; ++ GMemChunk *mem_chunk; ++ GSList *free_lists; /* implementation specific */ ++}; ++ ++G_LOCK_DEFINE_STATIC (current_allocator); ++static GAllocator *current_allocator = NULL; ++ ++/* HOLDS: current_allocator_lock */ ++static void ++g_slist_validate_allocator (GAllocator *allocator) ++{ ++ g_return_if_fail (allocator != NULL); ++ g_return_if_fail (allocator->is_unused == TRUE); ++ ++ if (allocator->type != G_ALLOCATOR_SLIST) ++ { ++ allocator->type = G_ALLOCATOR_SLIST; ++ if (allocator->mem_chunk) ++ { ++ g_mem_chunk_destroy (allocator->mem_chunk); ++ allocator->mem_chunk = NULL; ++ } ++ } ++ ++ if (!allocator->mem_chunk) ++ { ++ allocator->mem_chunk = g_mem_chunk_new (allocator->name, ++ sizeof (GSList), ++ sizeof (GSList) * allocator->n_preallocs, ++ G_ALLOC_ONLY); ++ allocator->free_lists = NULL; ++ } ++ ++ allocator->is_unused = FALSE; ++} ++ ++void ++g_slist_push_allocator (GAllocator *allocator) ++{ ++ G_LOCK (current_allocator); ++ g_slist_validate_allocator (allocator); ++ allocator->last = current_allocator; ++ current_allocator = allocator; ++ G_UNLOCK (current_allocator); ++} ++ ++void ++g_slist_pop_allocator (void) ++{ ++ G_LOCK (current_allocator); ++ if (current_allocator) ++ { ++ GAllocator *allocator; ++ ++ allocator = current_allocator; ++ current_allocator = allocator->last; ++ allocator->last = NULL; ++ allocator->is_unused = TRUE; ++ } ++ G_UNLOCK (current_allocator); ++} ++ ++GSList* ++g_slist_alloc (void) ++{ ++ GSList *list; ++ ++ G_LOCK (current_allocator); ++ if (!current_allocator) ++ { ++ GAllocator *allocator = g_allocator_new ("GLib default GSList allocator", ++ 128); ++ g_slist_validate_allocator (allocator); ++ allocator->last = NULL; ++ current_allocator = allocator; ++ } ++ if (!current_allocator->free_lists) ++ { ++ list = g_chunk_new (GSList, current_allocator->mem_chunk); ++ list->data = NULL; ++ } ++ else ++ { ++ if (current_allocator->free_lists->data) ++ { ++ list = current_allocator->free_lists->data; ++ current_allocator->free_lists->data = list->next; ++ list->data = NULL; ++ } ++ else ++ { ++ list = current_allocator->free_lists; ++ current_allocator->free_lists = list->next; ++ } ++ } ++ G_UNLOCK (current_allocator); ++ ++ list->next = NULL; ++ ++ return list; ++} ++ ++void ++g_slist_free (GSList *list) ++{ ++ if (list) ++ { ++ list->data = list->next; ++ G_LOCK (current_allocator); ++ list->next = current_allocator->free_lists; ++ current_allocator->free_lists = list; ++ G_UNLOCK (current_allocator); ++ } ++} ++ ++void ++g_slist_free_1 (GSList *list) ++{ ++ if (list) ++ { ++ list->data = NULL; ++ G_LOCK (current_allocator); ++ list->next = current_allocator->free_lists; ++ current_allocator->free_lists = list; ++ G_UNLOCK (current_allocator); ++ } ++} ++ ++GSList* ++g_slist_append (GSList *list, ++ gpointer data) ++{ ++ GSList *new_list; ++ GSList *last; ++ ++ new_list = g_slist_alloc (); ++ new_list->data = data; ++ ++ if (list) ++ { ++ last = g_slist_last (list); ++ /* g_assert (last != NULL); */ ++ last->next = new_list; ++ ++ return list; ++ } ++ else ++ return new_list; ++} ++ ++GSList* ++g_slist_prepend (GSList *list, ++ gpointer data) ++{ ++ GSList *new_list; ++ ++ new_list = g_slist_alloc (); ++ new_list->data = data; ++ new_list->next = list; ++ ++ return new_list; ++} ++ ++GSList* ++g_slist_insert (GSList *list, ++ gpointer data, ++ gint position) ++{ ++ GSList *prev_list; ++ GSList *tmp_list; ++ GSList *new_list; ++ ++ if (position < 0) ++ return g_slist_append (list, data); ++ else if (position == 0) ++ return g_slist_prepend (list, data); ++ ++ new_list = g_slist_alloc (); ++ new_list->data = data; ++ ++ if (!list) ++ return new_list; ++ ++ prev_list = NULL; ++ tmp_list = list; ++ ++ while ((position-- > 0) && tmp_list) ++ { ++ prev_list = tmp_list; ++ tmp_list = tmp_list->next; ++ } ++ ++ if (prev_list) ++ { ++ new_list->next = prev_list->next; ++ prev_list->next = new_list; ++ } ++ else ++ { ++ new_list->next = list; ++ list = new_list; ++ } ++ ++ return list; ++} ++ ++GSList * ++g_slist_concat (GSList *list1, GSList *list2) ++{ ++ if (list2) ++ { ++ if (list1) ++ g_slist_last (list1)->next = list2; ++ else ++ list1 = list2; ++ } ++ ++ return list1; ++} ++ ++GSList* ++g_slist_remove (GSList *list, ++ gpointer data) ++{ ++ GSList *tmp; ++ GSList *prev; ++ ++ prev = NULL; ++ tmp = list; ++ ++ while (tmp) ++ { ++ if (tmp->data == data) ++ { ++ if (prev) ++ prev->next = tmp->next; ++ if (list == tmp) ++ list = list->next; ++ ++ tmp->next = NULL; ++ g_slist_free (tmp); ++ ++ break; ++ } ++ ++ prev = tmp; ++ tmp = tmp->next; ++ } ++ ++ return list; ++} ++ ++GSList* ++g_slist_remove_link (GSList *list, ++ GSList *link) ++{ ++ GSList *tmp; ++ GSList *prev; ++ ++ prev = NULL; ++ tmp = list; ++ ++ while (tmp) ++ { ++ if (tmp == link) ++ { ++ if (prev) ++ prev->next = tmp->next; ++ if (list == tmp) ++ list = list->next; ++ ++ tmp->next = NULL; ++ break; ++ } ++ ++ prev = tmp; ++ tmp = tmp->next; ++ } ++ ++ return list; ++} ++ ++GSList* ++g_slist_copy (GSList *list) ++{ ++ GSList *new_list = NULL; ++ ++ if (list) ++ { ++ GSList *last; ++ ++ new_list = g_slist_alloc (); ++ new_list->data = list->data; ++ last = new_list; ++ list = list->next; ++ while (list) ++ { ++ last->next = g_slist_alloc (); ++ last = last->next; ++ last->data = list->data; ++ list = list->next; ++ } ++ } ++ ++ return new_list; ++} ++ ++GSList* ++g_slist_reverse (GSList *list) ++{ ++ GSList *prev = NULL; ++ ++ while (list) ++ { ++ GSList *next = list->next; ++ ++ list->next = prev; ++ ++ prev = list; ++ list = next; ++ } ++ ++ return prev; ++} ++ ++GSList* ++g_slist_nth (GSList *list, ++ guint n) ++{ ++ while ((n-- > 0) && list) ++ list = list->next; ++ ++ return list; ++} ++ ++gpointer ++g_slist_nth_data (GSList *list, ++ guint n) ++{ ++ while ((n-- > 0) && list) ++ list = list->next; ++ ++ return list ? list->data : NULL; ++} ++ ++GSList* ++g_slist_find (GSList *list, ++ gpointer data) ++{ ++ while (list) ++ { ++ if (list->data == data) ++ break; ++ list = list->next; ++ } ++ ++ return list; ++} ++ ++GSList* ++g_slist_find_custom (GSList *list, ++ gpointer data, ++ GCompareFunc func) ++{ ++ g_return_val_if_fail (func != NULL, list); ++ ++ while (list) ++ { ++ if (! func (list->data, data)) ++ return list; ++ list = list->next; ++ } ++ ++ return NULL; ++} ++ ++gint ++g_slist_position (GSList *list, ++ GSList *link) ++{ ++ gint i; ++ ++ i = 0; ++ while (list) ++ { ++ if (list == link) ++ return i; ++ i++; ++ list = list->next; ++ } ++ ++ return -1; ++} ++ ++gint ++g_slist_index (GSList *list, ++ gpointer data) ++{ ++ gint i; ++ ++ i = 0; ++ while (list) ++ { ++ if (list->data == data) ++ return i; ++ i++; ++ list = list->next; ++ } ++ ++ return -1; ++} ++ ++GSList* ++g_slist_last (GSList *list) ++{ ++ if (list) ++ { ++ while (list->next) ++ list = list->next; ++ } ++ ++ return list; ++} ++ ++guint ++g_slist_length (GSList *list) ++{ ++ guint length; ++ ++ length = 0; ++ while (list) ++ { ++ length++; ++ list = list->next; ++ } ++ ++ return length; ++} ++ ++void ++g_slist_foreach (GSList *list, ++ GFunc func, ++ gpointer user_data) ++{ ++ while (list) ++ { ++ (*func) (list->data, user_data); ++ list = list->next; ++ } ++} ++ ++GSList* ++g_slist_insert_sorted (GSList *list, ++ gpointer data, ++ GCompareFunc func) ++{ ++ GSList *tmp_list = list; ++ GSList *prev_list = NULL; ++ GSList *new_list; ++ gint cmp; ++ ++ g_return_val_if_fail (func != NULL, list); ++ ++ if (!list) ++ { ++ new_list = g_slist_alloc(); ++ new_list->data = data; ++ return new_list; ++ } ++ ++ cmp = (*func) (data, tmp_list->data); ++ ++ while ((tmp_list->next) && (cmp > 0)) ++ { ++ prev_list = tmp_list; ++ tmp_list = tmp_list->next; ++ cmp = (*func) (data, tmp_list->data); ++ } ++ ++ new_list = g_slist_alloc(); ++ new_list->data = data; ++ ++ if ((!tmp_list->next) && (cmp > 0)) ++ { ++ tmp_list->next = new_list; ++ return list; ++ } ++ ++ if (prev_list) ++ { ++ prev_list->next = new_list; ++ new_list->next = tmp_list; ++ return list; ++ } ++ else ++ { ++ new_list->next = list; ++ return new_list; ++ } ++} ++ ++static GSList* ++g_slist_sort_merge (GSList *l1, ++ GSList *l2, ++ GCompareFunc compare_func) ++{ ++ GSList list, *l; ++ ++ l=&list; ++ ++ while (l1 && l2) ++ { ++ if (compare_func(l1->data,l2->data) < 0) ++ { ++ l=l->next=l1; ++ l1=l1->next; ++ } ++ else ++ { ++ l=l->next=l2; ++ l2=l2->next; ++ } ++ } ++ l->next= l1 ? l1 : l2; ++ ++ return list.next; ++} ++ ++GSList* ++g_slist_sort (GSList *list, ++ GCompareFunc compare_func) ++{ ++ GSList *l1, *l2; ++ ++ if (!list) ++ return NULL; ++ if (!list->next) ++ return list; ++ ++ l1 = list; ++ l2 = list->next; ++ ++ while ((l2 = l2->next) != NULL) ++ { ++ if ((l2 = l2->next) == NULL) ++ break; ++ l1=l1->next; ++ } ++ l2 = l1->next; ++ l1->next = NULL; ++ ++ return g_slist_sort_merge (g_slist_sort (list, compare_func), ++ g_slist_sort (l2, compare_func), ++ compare_func); ++} +diff -urN linux-2.4.1/net/korbit/kglib/gstrfuncs.c linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c +--- linux-2.4.1/net/korbit/kglib/gstrfuncs.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gstrfuncs.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,1308 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <locale.h> ++#include <ctype.h> /* For tolower() */ ++#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL) ++#include <signal.h> ++#endif ++#include "glib.h" ++/* do not include <unistd.h> in this place since it ++ * inteferes with g_strsignal() on some OSes ++ */ ++ ++gchar* ++g_strdup (const gchar *str) { ++ gchar *new_str; ++ ++ if (str) ++ { ++ new_str = g_new (char, strlen (str) + 1); ++ strcpy (new_str, str); ++ } ++ else ++ new_str = NULL; ++ ++ return new_str; ++} ++ ++gpointer ++g_memdup (gconstpointer mem, ++ guint byte_size) ++{ ++ gpointer new_mem; ++ ++ if (mem) ++ { ++ new_mem = g_malloc (byte_size); ++ memcpy (new_mem, mem, byte_size); ++ } ++ else ++ new_mem = NULL; ++ ++ return new_mem; ++} ++ ++gchar* ++g_strndup (const gchar *str, ++ guint n) ++{ ++ gchar *new_str; ++ ++ if (str) ++ { ++ new_str = g_new (gchar, n + 1); ++ strncpy (new_str, str, n); ++ new_str[n] = '\0'; ++ } ++ else ++ new_str = NULL; ++ ++ return new_str; ++} ++ ++gchar* ++g_strnfill (guint length, ++ gchar fill_char) ++{ ++ register gchar *str, *s, *end; ++ ++ str = g_new (gchar, length + 1); ++ s = str; ++ end = str + length; ++ while (s < end) ++ *(s++) = fill_char; ++ *s = 0; ++ ++ return str; ++} ++ ++gchar* ++g_strdup_vprintf (const gchar *format, ++ va_list args1) ++{ ++ gchar *buffer; ++ va_list args2; ++ ++ G_VA_COPY (args2, args1); ++ ++ buffer = g_new (gchar, g_printf_string_upper_bound (format, args1)); ++ ++ vsprintf (buffer, format, args2); ++ va_end (args2); ++ ++ return buffer; ++} ++ ++gchar* ++g_strdup_printf (const gchar *format, ++ ...) ++{ ++ gchar *buffer; ++ va_list args; ++ ++ va_start (args, format); ++ buffer = g_strdup_vprintf (format, args); ++ va_end (args); ++ ++ return buffer; ++} ++ ++gchar* ++g_strconcat (const gchar *string1, ...) ++{ ++ guint l; ++ va_list args; ++ gchar *s; ++ gchar *concat; ++ ++ g_return_val_if_fail (string1 != NULL, NULL); ++ ++ l = 1 + strlen (string1); ++ va_start (args, string1); ++ s = va_arg (args, gchar*); ++ while (s) ++ { ++ l += strlen (s); ++ s = va_arg (args, gchar*); ++ } ++ va_end (args); ++ ++ concat = g_new (gchar, l); ++ concat[0] = 0; ++ ++ strcat (concat, string1); ++ va_start (args, string1); ++ s = va_arg (args, gchar*); ++ while (s) ++ { ++ strcat (concat, s); ++ s = va_arg (args, gchar*); ++ } ++ va_end (args); ++ ++ return concat; ++} ++ ++#ifndef __KORBIT__ ++gdouble ++g_strtod (const gchar *nptr, ++ gchar **endptr) ++{ ++ gchar *fail_pos_1; ++ gchar *fail_pos_2; ++ gdouble val_1; ++ gdouble val_2 = 0; ++ ++ g_return_val_if_fail (nptr != NULL, 0); ++ ++ fail_pos_1 = NULL; ++ fail_pos_2 = NULL; ++ ++ val_1 = strtod (nptr, &fail_pos_1); ++ ++ if (fail_pos_1 && fail_pos_1[0] != 0) ++ { ++ gchar *old_locale; ++ ++ old_locale = g_strdup (setlocale (LC_NUMERIC, NULL)); ++ setlocale (LC_NUMERIC, "C"); ++ val_2 = strtod (nptr, &fail_pos_2); ++ setlocale (LC_NUMERIC, old_locale); ++ g_free (old_locale); ++ } ++ ++ if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2) ++ { ++ if (endptr) ++ *endptr = fail_pos_1; ++ return val_1; ++ } ++ else ++ { ++ if (endptr) ++ *endptr = fail_pos_2; ++ return val_2; ++ } ++} ++#endif /* !__KORBIT__ */ ++ ++gchar* ++g_strerror (gint errnum) ++{ ++#ifndef __KORBIT__ ++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; ++ char *msg; ++#endif ++ ++#ifdef __KORBIT__ ++#undef HAVE_STRERROR ++#define NO_SYS_ERRLIST 1 ++#endif ++ ++#if defined(HAVE_STRERROR) ++ return strerror (errnum); ++#elif NO_SYS_ERRLIST ++ switch (errnum) ++ { ++#ifdef E2BIG ++ case E2BIG: return "argument list too long"; ++#endif ++#ifdef EACCES ++ case EACCES: return "permission denied"; ++#endif ++#ifdef EADDRINUSE ++ case EADDRINUSE: return "address already in use"; ++#endif ++#ifdef EADDRNOTAVAIL ++ case EADDRNOTAVAIL: return "can't assign requested address"; ++#endif ++#ifdef EADV ++ case EADV: return "advertise error"; ++#endif ++#ifdef EAFNOSUPPORT ++ case EAFNOSUPPORT: return "address family not supported by protocol family"; ++#endif ++#ifdef EAGAIN ++ case EAGAIN: return "try again"; ++#endif ++#ifdef EALIGN ++ case EALIGN: return "EALIGN"; ++#endif ++#ifdef EALREADY ++ case EALREADY: return "operation already in progress"; ++#endif ++#ifdef EBADE ++ case EBADE: return "bad exchange descriptor"; ++#endif ++#ifdef EBADF ++ case EBADF: return "bad file number"; ++#endif ++#ifdef EBADFD ++ case EBADFD: return "file descriptor in bad state"; ++#endif ++#ifdef EBADMSG ++ case EBADMSG: return "not a data message"; ++#endif ++#ifdef EBADR ++ case EBADR: return "bad request descriptor"; ++#endif ++#ifdef EBADRPC ++ case EBADRPC: return "RPC structure is bad"; ++#endif ++#ifdef EBADRQC ++ case EBADRQC: return "bad request code"; ++#endif ++#ifdef EBADSLT ++ case EBADSLT: return "invalid slot"; ++#endif ++#ifdef EBFONT ++ case EBFONT: return "bad font file format"; ++#endif ++#ifdef EBUSY ++ case EBUSY: return "mount device busy"; ++#endif ++#ifdef ECHILD ++ case ECHILD: return "no children"; ++#endif ++#ifdef ECHRNG ++ case ECHRNG: return "channel number out of range"; ++#endif ++#ifdef ECOMM ++ case ECOMM: return "communication error on send"; ++#endif ++#ifdef ECONNABORTED ++ case ECONNABORTED: return "software caused connection abort"; ++#endif ++#ifdef ECONNREFUSED ++ case ECONNREFUSED: return "connection refused"; ++#endif ++#ifdef ECONNRESET ++ case ECONNRESET: return "connection reset by peer"; ++#endif ++#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) && (!defined(EDEADLOCK) || (EDEADLK != EDEADLOCK)) ++ case EDEADLK: return "resource deadlock avoided"; ++#endif ++#ifdef EDEADLOCK ++ case EDEADLOCK: return "resource deadlock avoided"; ++#endif ++#ifdef EDESTADDRREQ ++ case EDESTADDRREQ: return "destination address required"; ++#endif ++#ifdef EDIRTY ++ case EDIRTY: return "mounting a dirty fs w/o force"; ++#endif ++#ifdef EDOM ++ case EDOM: return "math argument out of range"; ++#endif ++#ifdef EDOTDOT ++ case EDOTDOT: return "cross mount point"; ++#endif ++#ifdef EDQUOT ++ case EDQUOT: return "disk quota exceeded"; ++#endif ++#ifdef EDUPPKG ++ case EDUPPKG: return "duplicate package name"; ++#endif ++#ifdef EEXIST ++ case EEXIST: return "file already exists"; ++#endif ++#ifdef EFAULT ++ case EFAULT: return "bad address in system call argument"; ++#endif ++#ifdef EFBIG ++ case EFBIG: return "file too large"; ++#endif ++#ifdef EHOSTDOWN ++ case EHOSTDOWN: return "host is down"; ++#endif ++#ifdef EHOSTUNREACH ++ case EHOSTUNREACH: return "host is unreachable"; ++#endif ++#ifdef EIDRM ++ case EIDRM: return "identifier removed"; ++#endif ++#ifdef EINIT ++ case EINIT: return "initialization error"; ++#endif ++#ifdef EINPROGRESS ++ case EINPROGRESS: return "operation now in progress"; ++#endif ++#ifdef EINTR ++ case EINTR: return "interrupted system call"; ++#endif ++#ifdef EINVAL ++ case EINVAL: return "invalid argument"; ++#endif ++#ifdef EIO ++ case EIO: return "I/O error"; ++#endif ++#ifdef EISCONN ++ case EISCONN: return "socket is already connected"; ++#endif ++#ifdef EISDIR ++ case EISDIR: return "illegal operation on a directory"; ++#endif ++#ifdef EISNAME ++ case EISNAM: return "is a name file"; ++#endif ++#ifdef ELBIN ++ case ELBIN: return "ELBIN"; ++#endif ++#ifdef EL2HLT ++ case EL2HLT: return "level 2 halted"; ++#endif ++#ifdef EL2NSYNC ++ case EL2NSYNC: return "level 2 not synchronized"; ++#endif ++#ifdef EL3HLT ++ case EL3HLT: return "level 3 halted"; ++#endif ++#ifdef EL3RST ++ case EL3RST: return "level 3 reset"; ++#endif ++#ifdef ELIBACC ++ case ELIBACC: return "can not access a needed shared library"; ++#endif ++#ifdef ELIBBAD ++ case ELIBBAD: return "accessing a corrupted shared library"; ++#endif ++#ifdef ELIBEXEC ++ case ELIBEXEC: return "can not exec a shared library directly"; ++#endif ++#ifdef ELIBMAX ++ case ELIBMAX: return "attempting to link in more shared libraries than system limit"; ++#endif ++#ifdef ELIBSCN ++ case ELIBSCN: return ".lib section in a.out corrupted"; ++#endif ++#ifdef ELNRNG ++ case ELNRNG: return "link number out of range"; ++#endif ++#ifdef ELOOP ++ case ELOOP: return "too many levels of symbolic links"; ++#endif ++#ifdef EMFILE ++ case EMFILE: return "too many open files"; ++#endif ++#ifdef EMLINK ++ case EMLINK: return "too many links"; ++#endif ++#ifdef EMSGSIZE ++ case EMSGSIZE: return "message too long"; ++#endif ++#ifdef EMULTIHOP ++ case EMULTIHOP: return "multihop attempted"; ++#endif ++#ifdef ENAMETOOLONG ++ case ENAMETOOLONG: return "file name too long"; ++#endif ++#ifdef ENAVAIL ++ case ENAVAIL: return "not available"; ++#endif ++#ifdef ENET ++ case ENET: return "ENET"; ++#endif ++#ifdef ENETDOWN ++ case ENETDOWN: return "network is down"; ++#endif ++#ifdef ENETRESET ++ case ENETRESET: return "network dropped connection on reset"; ++#endif ++#ifdef ENETUNREACH ++ case ENETUNREACH: return "network is unreachable"; ++#endif ++#ifdef ENFILE ++ case ENFILE: return "file table overflow"; ++#endif ++#ifdef ENOANO ++ case ENOANO: return "anode table overflow"; ++#endif ++#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) ++ case ENOBUFS: return "no buffer space available"; ++#endif ++#ifdef ENOCSI ++ case ENOCSI: return "no CSI structure available"; ++#endif ++#ifdef ENODATA ++ case ENODATA: return "no data available"; ++#endif ++#ifdef ENODEV ++ case ENODEV: return "no such device"; ++#endif ++#ifdef ENOENT ++ case ENOENT: return "no such file or directory"; ++#endif ++#ifdef ENOEXEC ++ case ENOEXEC: return "exec format error"; ++#endif ++#ifdef ENOLCK ++ case ENOLCK: return "no locks available"; ++#endif ++#ifdef ENOLINK ++ case ENOLINK: return "link has be severed"; ++#endif ++#ifdef ENOMEM ++ case ENOMEM: return "not enough memory"; ++#endif ++#ifdef ENOMSG ++ case ENOMSG: return "no message of desired type"; ++#endif ++#ifdef ENONET ++ case ENONET: return "machine is not on the network"; ++#endif ++#ifdef ENOPKG ++ case ENOPKG: return "package not installed"; ++#endif ++#ifdef ENOPROTOOPT ++ case ENOPROTOOPT: return "bad proocol option"; ++#endif ++#ifdef ENOSPC ++ case ENOSPC: return "no space left on device"; ++#endif ++#ifdef ENOSR ++ case ENOSR: return "out of stream resources"; ++#endif ++#ifdef ENOSTR ++ case ENOSTR: return "not a stream device"; ++#endif ++#ifdef ENOSYM ++ case ENOSYM: return "unresolved symbol name"; ++#endif ++#ifdef ENOSYS ++ case ENOSYS: return "function not implemented"; ++#endif ++#ifdef ENOTBLK ++ case ENOTBLK: return "block device required"; ++#endif ++#ifdef ENOTCONN ++ case ENOTCONN: return "socket is not connected"; ++#endif ++#ifdef ENOTDIR ++ case ENOTDIR: return "not a directory"; ++#endif ++#ifdef ENOTEMPTY ++ case ENOTEMPTY: return "directory not empty"; ++#endif ++#ifdef ENOTNAM ++ case ENOTNAM: return "not a name file"; ++#endif ++#ifdef ENOTSOCK ++ case ENOTSOCK: return "socket operation on non-socket"; ++#endif ++#ifdef ENOTTY ++ case ENOTTY: return "inappropriate device for ioctl"; ++#endif ++#ifdef ENOTUNIQ ++ case ENOTUNIQ: return "name not unique on network"; ++#endif ++#ifdef ENXIO ++ case ENXIO: return "no such device or address"; ++#endif ++#ifdef EOPNOTSUPP ++ case EOPNOTSUPP: return "operation not supported on socket"; ++#endif ++#ifdef EPERM ++ case EPERM: return "not owner"; ++#endif ++#ifdef EPFNOSUPPORT ++ case EPFNOSUPPORT: return "protocol family not supported"; ++#endif ++#ifdef EPIPE ++ case EPIPE: return "broken pipe"; ++#endif ++#ifdef EPROCLIM ++ case EPROCLIM: return "too many processes"; ++#endif ++#ifdef EPROCUNAVAIL ++ case EPROCUNAVAIL: return "bad procedure for program"; ++#endif ++#ifdef EPROGMISMATCH ++ case EPROGMISMATCH: return "program version wrong"; ++#endif ++#ifdef EPROGUNAVAIL ++ case EPROGUNAVAIL: return "RPC program not available"; ++#endif ++#ifdef EPROTO ++ case EPROTO: return "protocol error"; ++#endif ++#ifdef EPROTONOSUPPORT ++ case EPROTONOSUPPORT: return "protocol not suppored"; ++#endif ++#ifdef EPROTOTYPE ++ case EPROTOTYPE: return "protocol wrong type for socket"; ++#endif ++#ifdef ERANGE ++ case ERANGE: return "math result unrepresentable"; ++#endif ++#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) ++ case EREFUSED: return "EREFUSED"; ++#endif ++#ifdef EREMCHG ++ case EREMCHG: return "remote address changed"; ++#endif ++#ifdef EREMDEV ++ case EREMDEV: return "remote device"; ++#endif ++#ifdef EREMOTE ++ case EREMOTE: return "pathname hit remote file system"; ++#endif ++#ifdef EREMOTEIO ++ case EREMOTEIO: return "remote i/o error"; ++#endif ++#ifdef EREMOTERELEASE ++ case EREMOTERELEASE: return "EREMOTERELEASE"; ++#endif ++#ifdef EROFS ++ case EROFS: return "read-only file system"; ++#endif ++#ifdef ERPCMISMATCH ++ case ERPCMISMATCH: return "RPC version is wrong"; ++#endif ++#ifdef ERREMOTE ++ case ERREMOTE: return "object is remote"; ++#endif ++#ifdef ESHUTDOWN ++ case ESHUTDOWN: return "can't send afer socket shutdown"; ++#endif ++#ifdef ESOCKTNOSUPPORT ++ case ESOCKTNOSUPPORT: return "socket type not supported"; ++#endif ++#ifdef ESPIPE ++ case ESPIPE: return "invalid seek"; ++#endif ++#ifdef ESRCH ++ case ESRCH: return "no such process"; ++#endif ++#ifdef ESRMNT ++ case ESRMNT: return "srmount error"; ++#endif ++#ifdef ESTALE ++ case ESTALE: return "stale remote file handle"; ++#endif ++#ifdef ESUCCESS ++ case ESUCCESS: return "Error 0"; ++#endif ++#ifdef ETIME ++ case ETIME: return "timer expired"; ++#endif ++#ifdef ETIMEDOUT ++ case ETIMEDOUT: return "connection timed out"; ++#endif ++#ifdef ETOOMANYREFS ++ case ETOOMANYREFS: return "too many references: can't splice"; ++#endif ++#ifdef ETXTBSY ++ case ETXTBSY: return "text file or pseudo-device busy"; ++#endif ++#ifdef EUCLEAN ++ case EUCLEAN: return "structure needs cleaning"; ++#endif ++#ifdef EUNATCH ++ case EUNATCH: return "protocol driver not attached"; ++#endif ++#ifdef EUSERS ++ case EUSERS: return "too many users"; ++#endif ++#ifdef EVERSION ++ case EVERSION: return "version mismatch"; ++#endif ++#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) ++ case EWOULDBLOCK: return "operation would block"; ++#endif ++#ifdef EXDEV ++ case EXDEV: return "cross-domain link"; ++#endif ++#ifdef EXFULL ++ case EXFULL: return "message tables full"; ++#endif ++ } ++#else /* NO_SYS_ERRLIST */ ++ extern int sys_nerr; ++ extern char *sys_errlist[]; ++ ++ if ((errnum > 0) && (errnum <= sys_nerr)) ++ return sys_errlist [errnum]; ++#endif /* NO_SYS_ERRLIST */ ++ ++#ifndef __KORBIT__ ++ msg = g_static_private_get (&msg_private); ++ if (!msg) ++ { ++ msg = g_new (gchar, 64); ++ g_static_private_set (&msg_private, msg, g_free); ++ } ++ ++ sprintf (msg, "unknown error (%d)", errnum); ++ ++ return msg; ++#else ++ return "unknown error"; ++#endif /* !__KORBIT__ */ ++} ++ ++gchar* ++g_strsignal (gint signum) ++{ ++#ifndef __KORBIT__ ++ static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT; ++ char *msg; ++#endif ++ ++#ifdef HAVE_STRSIGNAL ++ extern char *strsignal (int sig); ++ return strsignal (signum); ++#elif NO_SYS_SIGLIST ++ switch (signum) ++ { ++#ifdef SIGHUP ++ case SIGHUP: return "Hangup"; ++#endif ++#ifdef SIGINT ++ case SIGINT: return "Interrupt"; ++#endif ++#ifdef SIGQUIT ++ case SIGQUIT: return "Quit"; ++#endif ++#ifdef SIGILL ++ case SIGILL: return "Illegal instruction"; ++#endif ++#ifdef SIGTRAP ++ case SIGTRAP: return "Trace/breakpoint trap"; ++#endif ++#ifdef SIGABRT ++ case SIGABRT: return "IOT trap/Abort"; ++#endif ++#ifdef SIGBUS ++ case SIGBUS: return "Bus error"; ++#endif ++#ifdef SIGFPE ++ case SIGFPE: return "Floating point exception"; ++#endif ++#ifdef SIGKILL ++ case SIGKILL: return "Killed"; ++#endif ++#ifdef SIGUSR1 ++ case SIGUSR1: return "User defined signal 1"; ++#endif ++#ifdef SIGSEGV ++ case SIGSEGV: return "Segmentation fault"; ++#endif ++#ifdef SIGUSR2 ++ case SIGUSR2: return "User defined signal 2"; ++#endif ++#ifdef SIGPIPE ++ case SIGPIPE: return "Broken pipe"; ++#endif ++#ifdef SIGALRM ++ case SIGALRM: return "Alarm clock"; ++#endif ++#ifdef SIGTERM ++ case SIGTERM: return "Terminated"; ++#endif ++#ifdef SIGSTKFLT ++ case SIGSTKFLT: return "Stack fault"; ++#endif ++#ifdef SIGCHLD ++ case SIGCHLD: return "Child exited"; ++#endif ++#ifdef SIGCONT ++ case SIGCONT: return "Continued"; ++#endif ++#ifdef SIGSTOP ++ case SIGSTOP: return "Stopped (signal)"; ++#endif ++#ifdef SIGTSTP ++ case SIGTSTP: return "Stopped"; ++#endif ++#ifdef SIGTTIN ++ case SIGTTIN: return "Stopped (tty input)"; ++#endif ++#ifdef SIGTTOU ++ case SIGTTOU: return "Stopped (tty output)"; ++#endif ++#ifdef SIGURG ++ case SIGURG: return "Urgent condition"; ++#endif ++#ifdef SIGXCPU ++ case SIGXCPU: return "CPU time limit exceeded"; ++#endif ++#ifdef SIGXFSZ ++ case SIGXFSZ: return "File size limit exceeded"; ++#endif ++#ifdef SIGVTALRM ++ case SIGVTALRM: return "Virtual time alarm"; ++#endif ++#ifdef SIGPROF ++ case SIGPROF: return "Profile signal"; ++#endif ++#ifdef SIGWINCH ++ case SIGWINCH: return "Window size changed"; ++#endif ++#ifdef SIGIO ++ case SIGIO: return "Possible I/O"; ++#endif ++#ifdef SIGPWR ++ case SIGPWR: return "Power failure"; ++#endif ++#ifdef SIGUNUSED ++ case SIGUNUSED: return "Unused signal"; ++#endif ++ } ++#else /* NO_SYS_SIGLIST */ ++ ++#ifdef NO_SYS_SIGLIST_DECL ++ extern char *sys_siglist[]; /*(see Tue Jan 19 00:44:24 1999 in changelog)*/ ++#endif ++ ++ return (char*) /* this function should return const --josh */ sys_siglist [signum]; ++#endif /* NO_SYS_SIGLIST */ ++ ++#ifndef __KORBIT__ ++ msg = g_static_private_get (&msg_private); ++ if (!msg) ++ { ++ msg = g_new (gchar, 64); ++ g_static_private_set (&msg_private, msg, g_free); ++ } ++ ++ sprintf (msg, "unknown signal (%d)", signum); ++ ++ return msg; ++#else ++ return "unknown error"; ++#endif /* !__KORBIT__ */ ++} ++ ++guint ++g_printf_string_upper_bound (const gchar* format, ++ va_list args) ++{ ++ guint len = 1; ++ ++ while (*format) ++ { ++ gboolean long_int = FALSE; ++ gboolean extra_long = FALSE; ++ gchar c; ++ ++ c = *format++; ++ ++ if (c == '%') ++ { ++ gboolean done = FALSE; ++ ++ while (*format && !done) ++ { ++ switch (*format++) ++ { ++ gchar *string_arg; ++ ++ case '*': ++ len += va_arg (args, int); ++ break; ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ /* add specified format length, since it might exceed the ++ * size we assume it to have. ++ */ ++ format -= 1; ++ len += strtol (format, (char**) &format, 10); ++ break; ++ case 'h': ++ /* ignore short int flag, since all args have at least the ++ * same size as an int ++ */ ++ break; ++ case 'l': ++ if (long_int) ++ extra_long = TRUE; /* linux specific */ ++ else ++ long_int = TRUE; ++ break; ++ case 'q': ++ case 'L': ++ long_int = TRUE; ++ extra_long = TRUE; ++ break; ++ case 's': ++ string_arg = va_arg (args, char *); ++ if (string_arg) ++ len += strlen (string_arg); ++ else ++ { ++ /* add enough padding to hold "(null)" identifier */ ++ len += 16; ++ } ++ done = TRUE; ++ break; ++ case 'd': ++ case 'i': ++ case 'o': ++ case 'u': ++ case 'x': ++ case 'X': ++#ifdef G_HAVE_GINT64 ++ if (extra_long) ++ (void) va_arg (args, gint64); ++ else ++#endif /* G_HAVE_GINT64 */ ++ { ++ if (long_int) ++ (void) va_arg (args, long); ++ else ++ (void) va_arg (args, int); ++ } ++ len += extra_long ? 64 : 32; ++ done = TRUE; ++ break; ++ case 'D': ++ case 'O': ++ case 'U': ++ (void) va_arg (args, long); ++ len += 32; ++ done = TRUE; ++ break; ++ case 'e': ++ case 'E': ++ case 'f': ++ case 'g': ++#ifdef HAVE_LONG_DOUBLE ++ if (extra_long) ++ (void) va_arg (args, long double); ++ else ++#endif /* HAVE_LONG_DOUBLE */ ++ (void) va_arg (args, double); ++ len += extra_long ? 128 : 64; ++ done = TRUE; ++ break; ++ case 'c': ++ (void) va_arg (args, int); ++ len += 1; ++ done = TRUE; ++ break; ++ case 'p': ++ case 'n': ++ (void) va_arg (args, void*); ++ len += 32; ++ done = TRUE; ++ break; ++ case '%': ++ len += 1; ++ done = TRUE; ++ break; ++ default: ++ /* ignore unknow/invalid flags */ ++ break; ++ } ++ } ++ } ++ else ++ len += 1; ++ } ++ ++ return len; ++} ++ ++void ++g_strdown (gchar *string) ++{ ++ register guchar *s; ++ ++ g_return_if_fail (string != NULL); ++ ++ s = string; ++ ++ while (*s) ++ { ++ *s = tolower (*s); ++ s++; ++ } ++} ++ ++void ++g_strup (gchar *string) ++{ ++ register guchar *s; ++ ++ g_return_if_fail (string != NULL); ++ ++ s = string; ++ ++ while (*s) ++ { ++ *s = toupper (*s); ++ s++; ++ } ++} ++ ++void ++g_strreverse (gchar *string) ++{ ++ g_return_if_fail (string != NULL); ++ ++ if (*string) ++ { ++ register gchar *h, *t; ++ ++ h = string; ++ t = string + strlen (string) - 1; ++ ++ while (h < t) ++ { ++ register gchar c; ++ ++ c = *h; ++ *h = *t; ++ h++; ++ *t = c; ++ t--; ++ } ++ } ++} ++ ++gint ++g_strcasecmp (const gchar *s1, ++ const gchar *s2) ++{ ++#ifdef HAVE_STRCASECMP ++ g_return_val_if_fail (s1 != NULL, 0); ++ g_return_val_if_fail (s2 != NULL, 0); ++ ++ return strcasecmp (s1, s2); ++#else ++ gint c1, c2; ++ ++ g_return_val_if_fail (s1 != NULL, 0); ++ g_return_val_if_fail (s2 != NULL, 0); ++ ++ while (*s1 && *s2) ++ { ++ /* According to A. Cox, some platforms have islower's that ++ * don't work right on non-uppercase ++ */ ++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1; ++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2; ++ if (c1 != c2) ++ return (c1 - c2); ++ s1++; s2++; ++ } ++ ++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2)); ++#endif ++} ++ ++gint ++g_strncasecmp (const gchar *s1, ++ const gchar *s2, ++ guint n) ++{ ++#ifdef HAVE_STRNCASECMP ++ return strncasecmp (s1, s2, n); ++#else ++ gint c1, c2; ++ ++ g_return_val_if_fail (s1 != NULL, 0); ++ g_return_val_if_fail (s2 != NULL, 0); ++ ++ while (n-- && *s1 && *s2) ++ { ++ /* According to A. Cox, some platforms have islower's that ++ * don't work right on non-uppercase ++ */ ++ c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1; ++ c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2; ++ if (c1 != c2) ++ return (c1 - c2); ++ s1++; s2++; ++ } ++ ++ if (n) ++ return (((gint)(guchar) *s1) - ((gint)(guchar) *s2)); ++ else ++ return 0; ++#endif ++} ++ ++gchar* ++g_strdelimit (gchar *string, ++ const gchar *delimiters, ++ gchar new_delim) ++{ ++ register gchar *c; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ if (!delimiters) ++ delimiters = G_STR_DELIMITERS; ++ ++ for (c = string; *c; c++) ++ { ++ if (strchr (delimiters, *c)) ++ *c = new_delim; ++ } ++ ++ return string; ++} ++ ++gchar* ++g_strescape (gchar *string) ++{ ++ gchar *q; ++ gchar *escaped; ++ guint backslashes = 0; ++ gchar *p = string; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ while (*p != '\000') ++ backslashes += (*p++ == '\\'); ++ ++ if (!backslashes) ++ return g_strdup (string); ++ ++ escaped = g_new (gchar, strlen (string) + backslashes + 1); ++ ++ p = string; ++ q = escaped; ++ ++ while (*p != '\000') ++ { ++ if (*p == '\\') ++ *q++ = '\\'; ++ *q++ = *p++; ++ } ++ *q = '\000'; ++ ++ return escaped; ++} ++ ++/* blame Elliot for these next five routines */ ++gchar* ++g_strchug (gchar *string) ++{ ++ guchar *start; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ for (start = string; *start && isspace (*start); start++) ++ ; ++ ++ g_memmove(string, start, strlen(start) + 1); ++ ++ return string; ++} ++ ++gchar* ++g_strchomp (gchar *string) ++{ ++ gchar *s; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ if (!*string) ++ return string; ++ ++ for (s = string + strlen (string) - 1; s >= string && isspace ((guchar)*s); ++ s--) ++ *s = '\0'; ++ ++ return string; ++} ++ ++gchar** ++g_strsplit (const gchar *string, ++ const gchar *delimiter, ++ gint max_tokens) ++{ ++ GSList *string_list = NULL, *slist; ++ gchar **str_array, *s; ++ guint i, n = 1; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (delimiter != NULL, NULL); ++ ++ if (max_tokens < 1) ++ max_tokens = G_MAXINT; ++ ++ s = strstr (string, delimiter); ++ if (s) ++ { ++ guint delimiter_len = strlen (delimiter); ++ ++ do ++ { ++ guint len; ++ gchar *new_string; ++ ++ len = s - string; ++ new_string = g_new (gchar, len + 1); ++ strncpy (new_string, string, len); ++ new_string[len] = 0; ++ string_list = g_slist_prepend (string_list, new_string); ++ n++; ++ string = s + delimiter_len; ++ s = strstr (string, delimiter); ++ } ++ while (--max_tokens && s); ++ } ++ if (*string) ++ { ++ n++; ++ string_list = g_slist_prepend (string_list, g_strdup (string)); ++ } ++ ++ str_array = g_new (gchar*, n); ++ ++ i = n - 1; ++ ++ str_array[i--] = NULL; ++ for (slist = string_list; slist; slist = slist->next) ++ str_array[i--] = slist->data; ++ ++ g_slist_free (string_list); ++ ++ return str_array; ++} ++ ++void ++g_strfreev (gchar **str_array) ++{ ++ if (str_array) ++ { ++ int i; ++ ++ for(i = 0; str_array[i] != NULL; i++) ++ g_free(str_array[i]); ++ ++ g_free (str_array); ++ } ++} ++ ++gchar* ++g_strjoinv (const gchar *separator, ++ gchar **str_array) ++{ ++ gchar *string; ++ ++ g_return_val_if_fail (str_array != NULL, NULL); ++ ++ if (separator == NULL) ++ separator = ""; ++ ++ if (*str_array) ++ { ++ guint i, len; ++ guint separator_len; ++ ++ separator_len = strlen (separator); ++ len = 1 + strlen (str_array[0]); ++ for(i = 1; str_array[i] != NULL; i++) ++ len += separator_len + strlen(str_array[i]); ++ ++ string = g_new (gchar, len); ++ *string = 0; ++ strcat (string, *str_array); ++ for (i = 1; str_array[i] != NULL; i++) ++ { ++ strcat (string, separator); ++ strcat (string, str_array[i]); ++ } ++ } ++ else ++ string = g_strdup (""); ++ ++ return string; ++} ++ ++gchar* ++g_strjoin (const gchar *separator, ++ ...) ++{ ++ gchar *string, *s; ++ va_list args; ++ guint len; ++ guint separator_len; ++ ++ if (separator == NULL) ++ separator = ""; ++ ++ separator_len = strlen (separator); ++ ++ va_start (args, separator); ++ ++ s = va_arg (args, gchar*); ++ ++ if (s) ++ { ++ len = strlen (s); ++ ++ s = va_arg (args, gchar*); ++ while (s) ++ { ++ len += separator_len + strlen (s); ++ s = va_arg (args, gchar*); ++ } ++ va_end (args); ++ ++ string = g_new (gchar, len + 1); ++ *string = 0; ++ ++ va_start (args, separator); ++ ++ s = va_arg (args, gchar*); ++ strcat (string, s); ++ ++ s = va_arg (args, gchar*); ++ while (s) ++ { ++ strcat (string, separator); ++ strcat (string, s); ++ s = va_arg (args, gchar*); ++ } ++ } ++ else ++ string = g_strdup (""); ++ ++ va_end (args); ++ ++ return string; ++} +diff -urN linux-2.4.1/net/korbit/kglib/gstring.c linux-2.4.1-korbit/net/korbit/kglib/gstring.c +--- linux-2.4.1/net/korbit/kglib/gstring.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gstring.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,508 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include <stdarg.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++#include <ctype.h> ++#include "glib.h" ++ ++ ++typedef struct _GRealStringChunk GRealStringChunk; ++typedef struct _GRealString GRealString; ++ ++struct _GRealStringChunk ++{ ++ GHashTable *const_table; ++ GSList *storage_list; ++ gint storage_next; ++ gint this_size; ++ gint default_size; ++}; ++ ++struct _GRealString ++{ ++ gchar *str; ++ gint len; ++ gint alloc; ++}; ++ ++G_LOCK_DEFINE_STATIC (string_mem_chunk); ++static GMemChunk *string_mem_chunk = NULL; ++ ++/* Hash Functions. ++ */ ++ ++gint ++g_str_equal (gconstpointer v, gconstpointer v2) ++{ ++ return strcmp ((const gchar*) v, (const gchar*)v2) == 0; ++} ++ ++/* 31 bit hash function */ ++guint ++g_str_hash (gconstpointer key) ++{ ++ const char *p = key; ++ guint h = *p; ++ ++ if (h) ++ for (p += 1; *p != '\0'; p++) ++ h = (h << 5) - h + *p; ++ ++ return h; ++} ++ ++/* String Chunks. ++ */ ++ ++GStringChunk* ++g_string_chunk_new (gint default_size) ++{ ++ GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1); ++ gint size = 1; ++ ++ while (size < default_size) ++ size <<= 1; ++ ++ new_chunk->const_table = NULL; ++ new_chunk->storage_list = NULL; ++ new_chunk->storage_next = size; ++ new_chunk->default_size = size; ++ new_chunk->this_size = size; ++ ++ return (GStringChunk*) new_chunk; ++} ++ ++void ++g_string_chunk_free (GStringChunk *fchunk) ++{ ++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk; ++ GSList *tmp_list; ++ ++ g_return_if_fail (chunk != NULL); ++ ++ if (chunk->storage_list) ++ { ++ for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next) ++ g_free (tmp_list->data); ++ ++ g_slist_free (chunk->storage_list); ++ } ++ ++ if (chunk->const_table) ++ g_hash_table_destroy (chunk->const_table); ++ ++ g_free (chunk); ++} ++ ++gchar* ++g_string_chunk_insert (GStringChunk *fchunk, ++ const gchar *string) ++{ ++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk; ++ gint len = strlen (string); ++ char* pos; ++ ++ g_return_val_if_fail (chunk != NULL, NULL); ++ ++ if ((chunk->storage_next + len + 1) > chunk->this_size) ++ { ++ gint new_size = chunk->default_size; ++ ++ while (new_size < len+1) ++ new_size <<= 1; ++ ++ chunk->storage_list = g_slist_prepend (chunk->storage_list, ++ g_new (char, new_size)); ++ ++ chunk->this_size = new_size; ++ chunk->storage_next = 0; ++ } ++ ++ pos = ((char*)chunk->storage_list->data) + chunk->storage_next; ++ ++ strcpy (pos, string); ++ ++ chunk->storage_next += len + 1; ++ ++ return pos; ++} ++ ++gchar* ++g_string_chunk_insert_const (GStringChunk *fchunk, ++ const gchar *string) ++{ ++ GRealStringChunk *chunk = (GRealStringChunk*) fchunk; ++ char* lookup; ++ ++ g_return_val_if_fail (chunk != NULL, NULL); ++ ++ if (!chunk->const_table) ++ chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal); ++ ++ lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string); ++ ++ if (!lookup) ++ { ++ lookup = g_string_chunk_insert (fchunk, string); ++ g_hash_table_insert (chunk->const_table, lookup, lookup); ++ } ++ ++ return lookup; ++} ++ ++/* Strings. ++ */ ++static gint ++nearest_pow (gint num) ++{ ++ gint n = 1; ++ ++ while (n < num) ++ n <<= 1; ++ ++ return n; ++} ++ ++static void ++g_string_maybe_expand (GRealString* string, gint len) ++{ ++ if (string->len + len >= string->alloc) ++ { ++ string->alloc = nearest_pow (string->len + len + 1); ++ string->str = g_realloc (string->str, string->alloc); ++ } ++} ++ ++GString* ++g_string_sized_new (guint dfl_size) ++{ ++ GRealString *string; ++ ++ G_LOCK (string_mem_chunk); ++ if (!string_mem_chunk) ++ string_mem_chunk = g_mem_chunk_new ("string mem chunk", ++ sizeof (GRealString), ++ 1024, G_ALLOC_AND_FREE); ++ ++ string = g_chunk_new (GRealString, string_mem_chunk); ++ G_UNLOCK (string_mem_chunk); ++ ++ string->alloc = 0; ++ string->len = 0; ++ string->str = NULL; ++ ++ g_string_maybe_expand (string, MAX (dfl_size, 2)); ++ string->str[0] = 0; ++ ++ return (GString*) string; ++} ++ ++GString* ++g_string_new (const gchar *init) ++{ ++ GString *string; ++ ++ string = g_string_sized_new (2); ++ ++ if (init) ++ g_string_append (string, init); ++ ++ return string; ++} ++ ++void ++g_string_free (GString *string, ++ gint free_segment) ++{ ++ g_return_if_fail (string != NULL); ++ ++ if (free_segment) ++ g_free (string->str); ++ ++ G_LOCK (string_mem_chunk); ++ g_mem_chunk_free (string_mem_chunk, string); ++ G_UNLOCK (string_mem_chunk); ++} ++ ++GString* ++g_string_assign (GString *lval, ++ const gchar *rval) ++{ ++ g_return_val_if_fail (lval != NULL, NULL); ++ g_return_val_if_fail (rval != NULL, NULL); ++ ++ g_string_truncate (lval, 0); ++ g_string_append (lval, rval); ++ ++ return lval; ++} ++ ++GString* ++g_string_truncate (GString* fstring, ++ gint len) ++{ ++ GRealString *string = (GRealString*)fstring; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (len >= 0, NULL); ++ ++ string->len = len; ++ ++ string->str[len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_append (GString *fstring, ++ const gchar *val) ++{ ++ GRealString *string = (GRealString*)fstring; ++ int len; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (val != NULL, fstring); ++ ++ len = strlen (val); ++ g_string_maybe_expand (string, len); ++ ++ strcpy (string->str + string->len, val); ++ ++ string->len += len; ++ ++ return fstring; ++} ++ ++GString* ++g_string_append_c (GString *fstring, ++ gchar c) ++{ ++ GRealString *string = (GRealString*)fstring; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_string_maybe_expand (string, 1); ++ ++ string->str[string->len++] = c; ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_prepend (GString *fstring, ++ const gchar *val) ++{ ++ GRealString *string = (GRealString*)fstring; ++ gint len; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (val != NULL, fstring); ++ ++ len = strlen (val); ++ g_string_maybe_expand (string, len); ++ ++ g_memmove (string->str + len, string->str, string->len); ++ ++ strncpy (string->str, val, len); ++ ++ string->len += len; ++ ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_prepend_c (GString *fstring, ++ gchar c) ++{ ++ GRealString *string = (GRealString*)fstring; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_string_maybe_expand (string, 1); ++ ++ g_memmove (string->str + 1, string->str, string->len); ++ ++ string->str[0] = c; ++ ++ string->len += 1; ++ ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_insert (GString *fstring, ++ gint pos, ++ const gchar *val) ++{ ++ GRealString *string = (GRealString*)fstring; ++ gint len; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (val != NULL, fstring); ++ g_return_val_if_fail (pos >= 0, fstring); ++ g_return_val_if_fail (pos <= string->len, fstring); ++ ++ len = strlen (val); ++ g_string_maybe_expand (string, len); ++ ++ g_memmove (string->str + pos + len, string->str + pos, string->len - pos); ++ ++ strncpy (string->str + pos, val, len); ++ ++ string->len += len; ++ ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString * ++g_string_insert_c (GString *fstring, ++ gint pos, ++ gchar c) ++{ ++ GRealString *string = (GRealString*)fstring; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (pos <= string->len, fstring); ++ ++ g_string_maybe_expand (string, 1); ++ ++ g_memmove (string->str + pos + 1, string->str + pos, string->len - pos); ++ ++ string->str[pos] = c; ++ ++ string->len += 1; ++ ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_erase (GString *fstring, ++ gint pos, ++ gint len) ++{ ++ GRealString *string = (GRealString*)fstring; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ g_return_val_if_fail (len >= 0, fstring); ++ g_return_val_if_fail (pos >= 0, fstring); ++ g_return_val_if_fail (pos <= string->len, fstring); ++ g_return_val_if_fail (pos + len <= string->len, fstring); ++ ++ if (pos + len < string->len) ++ g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len)); ++ ++ string->len -= len; ++ ++ string->str[string->len] = 0; ++ ++ return fstring; ++} ++ ++GString* ++g_string_down (GString *fstring) ++{ ++ GRealString *string = (GRealString*)fstring; ++ guchar *s; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ s = string->str; ++ ++ while (*s) ++ { ++ *s = tolower (*s); ++ s++; ++ } ++ ++ return fstring; ++} ++ ++GString* ++g_string_up (GString *fstring) ++{ ++ GRealString *string = (GRealString*)fstring; ++ guchar *s; ++ ++ g_return_val_if_fail (string != NULL, NULL); ++ ++ s = string->str; ++ ++ while (*s) ++ { ++ *s = toupper (*s); ++ s++; ++ } ++ ++ return fstring; ++} ++ ++static void ++g_string_sprintfa_int (GString *string, ++ const gchar *fmt, ++ va_list args) ++{ ++ gchar *buffer; ++ ++ buffer = g_strdup_vprintf (fmt, args); ++ g_string_append (string, buffer); ++ g_free (buffer); ++} ++ ++void ++g_string_sprintf (GString *string, ++ const gchar *fmt, ++ ...) ++{ ++ va_list args; ++ ++ g_string_truncate (string, 0); ++ ++ va_start (args, fmt); ++ g_string_sprintfa_int (string, fmt, args); ++ va_end (args); ++} ++ ++void ++g_string_sprintfa (GString *string, ++ const gchar *fmt, ++ ...) ++{ ++ va_list args; ++ ++ va_start (args, fmt); ++ g_string_sprintfa_int (string, fmt, args); ++ va_end (args); ++} +diff -urN linux-2.4.1/net/korbit/kglib/gtree.c linux-2.4.1-korbit/net/korbit/kglib/gtree.c +--- linux-2.4.1/net/korbit/kglib/gtree.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gtree.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,740 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#include "glib.h" ++ ++ ++typedef struct _GRealTree GRealTree; ++typedef struct _GTreeNode GTreeNode; ++ ++struct _GRealTree ++{ ++ GTreeNode *root; ++ GCompareFunc key_compare; ++}; ++ ++struct _GTreeNode ++{ ++ gint balance; /* height (left) - height (right) */ ++ GTreeNode *left; /* left subtree */ ++ GTreeNode *right; /* right subtree */ ++ gpointer key; /* key for this node */ ++ gpointer value; /* value stored at this node */ ++}; ++ ++ ++static GTreeNode* g_tree_node_new (gpointer key, ++ gpointer value); ++static void g_tree_node_destroy (GTreeNode *node); ++static GTreeNode* g_tree_node_insert (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key, ++ gpointer value, ++ gint *inserted); ++static GTreeNode* g_tree_node_remove (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key); ++static GTreeNode* g_tree_node_balance (GTreeNode *node); ++static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node, ++ GTreeNode **leftmost); ++static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node, ++ gint old_balance); ++static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node, ++ gint old_balance); ++static gpointer g_tree_node_lookup (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key); ++static gint g_tree_node_count (GTreeNode *node); ++static gint g_tree_node_pre_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data); ++static gint g_tree_node_in_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data); ++static gint g_tree_node_post_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data); ++static gpointer g_tree_node_search (GTreeNode *node, ++ GSearchFunc search_func, ++ gpointer data); ++static gint g_tree_node_height (GTreeNode *node); ++static GTreeNode* g_tree_node_rotate_left (GTreeNode *node); ++static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); ++static void g_tree_node_check (GTreeNode *node); ++ ++ ++G_LOCK_DEFINE_STATIC (g_tree_global); ++static GMemChunk *node_mem_chunk = NULL; ++static GTreeNode *node_free_list = NULL; ++ ++ ++static GTreeNode* ++g_tree_node_new (gpointer key, ++ gpointer value) ++{ ++ GTreeNode *node; ++ ++ G_LOCK (g_tree_global); ++ if (node_free_list) ++ { ++ node = node_free_list; ++ node_free_list = node->right; ++ } ++ else ++ { ++ if (!node_mem_chunk) ++ node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk", ++ sizeof (GTreeNode), ++ 1024, ++ G_ALLOC_ONLY); ++ ++ node = g_chunk_new (GTreeNode, node_mem_chunk); ++ } ++ G_UNLOCK (g_tree_global); ++ ++ node->balance = 0; ++ node->left = NULL; ++ node->right = NULL; ++ node->key = key; ++ node->value = value; ++ ++ return node; ++} ++ ++static void ++g_tree_node_destroy (GTreeNode *node) ++{ ++ if (node) ++ { ++ g_tree_node_destroy (node->right); ++ g_tree_node_destroy (node->left); ++ G_LOCK (g_tree_global); ++ node->right = node_free_list; ++ node_free_list = node; ++ G_UNLOCK (g_tree_global); ++ } ++} ++ ++ ++GTree* ++g_tree_new (GCompareFunc key_compare_func) ++{ ++ GRealTree *rtree; ++ ++ g_return_val_if_fail (key_compare_func != NULL, NULL); ++ ++ rtree = g_new (GRealTree, 1); ++ rtree->root = NULL; ++ rtree->key_compare = key_compare_func; ++ ++ return (GTree*) rtree; ++} ++ ++void ++g_tree_destroy (GTree *tree) ++{ ++ GRealTree *rtree; ++ ++ g_return_if_fail (tree != NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ g_tree_node_destroy (rtree->root); ++ g_free (rtree); ++} ++ ++void ++g_tree_insert (GTree *tree, ++ gpointer key, ++ gpointer value) ++{ ++ GRealTree *rtree; ++ gint inserted; ++ ++ g_return_if_fail (tree != NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ inserted = FALSE; ++ rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare, ++ key, value, &inserted); ++} ++ ++void ++g_tree_remove (GTree *tree, ++ gpointer key) ++{ ++ GRealTree *rtree; ++ ++ g_return_if_fail (tree != NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key); ++} ++ ++gpointer ++g_tree_lookup (GTree *tree, ++ gpointer key) ++{ ++ GRealTree *rtree; ++ ++ g_return_val_if_fail (tree != NULL, NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ return g_tree_node_lookup (rtree->root, rtree->key_compare, key); ++} ++ ++void ++g_tree_traverse (GTree *tree, ++ GTraverseFunc traverse_func, ++ GTraverseType traverse_type, ++ gpointer data) ++{ ++ GRealTree *rtree; ++ ++ g_return_if_fail (tree != NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ if (!rtree->root) ++ return; ++ ++ switch (traverse_type) ++ { ++ case G_PRE_ORDER: ++ g_tree_node_pre_order (rtree->root, traverse_func, data); ++ break; ++ ++ case G_IN_ORDER: ++ g_tree_node_in_order (rtree->root, traverse_func, data); ++ break; ++ ++ case G_POST_ORDER: ++ g_tree_node_post_order (rtree->root, traverse_func, data); ++ break; ++ ++ case G_LEVEL_ORDER: ++ g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented."); ++ break; ++ } ++} ++ ++gpointer ++g_tree_search (GTree *tree, ++ GSearchFunc search_func, ++ gpointer data) ++{ ++ GRealTree *rtree; ++ ++ g_return_val_if_fail (tree != NULL, NULL); ++ ++ rtree = (GRealTree*) tree; ++ ++ if (rtree->root) ++ return g_tree_node_search (rtree->root, search_func, data); ++ else ++ return NULL; ++} ++ ++gint ++g_tree_height (GTree *tree) ++{ ++ GRealTree *rtree; ++ ++ g_return_val_if_fail (tree != NULL, 0); ++ ++ rtree = (GRealTree*) tree; ++ ++ if (rtree->root) ++ return g_tree_node_height (rtree->root); ++ else ++ return 0; ++} ++ ++gint ++g_tree_nnodes (GTree *tree) ++{ ++ GRealTree *rtree; ++ ++ g_return_val_if_fail (tree != NULL, 0); ++ ++ rtree = (GRealTree*) tree; ++ ++ if (rtree->root) ++ return g_tree_node_count (rtree->root); ++ else ++ return 0; ++} ++ ++static GTreeNode* ++g_tree_node_insert (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key, ++ gpointer value, ++ gint *inserted) ++{ ++ gint old_balance; ++ gint cmp; ++ ++ if (!node) ++ { ++ *inserted = TRUE; ++ return g_tree_node_new (key, value); ++ } ++ ++ cmp = (* compare) (key, node->key); ++ if (cmp == 0) ++ { ++ *inserted = FALSE; ++ node->value = value; ++ return node; ++ } ++ ++ if (cmp < 0) ++ { ++ if (node->left) ++ { ++ old_balance = node->left->balance; ++ node->left = g_tree_node_insert (node->left, compare, key, value, inserted); ++ ++ if ((old_balance != node->left->balance) && node->left->balance) ++ node->balance -= 1; ++ } ++ else ++ { ++ *inserted = TRUE; ++ node->left = g_tree_node_new (key, value); ++ node->balance -= 1; ++ } ++ } ++ else if (cmp > 0) ++ { ++ if (node->right) ++ { ++ old_balance = node->right->balance; ++ node->right = g_tree_node_insert (node->right, compare, key, value, inserted); ++ ++ if ((old_balance != node->right->balance) && node->right->balance) ++ node->balance += 1; ++ } ++ else ++ { ++ *inserted = TRUE; ++ node->right = g_tree_node_new (key, value); ++ node->balance += 1; ++ } ++ } ++ ++ if (*inserted) ++ { ++ if ((node->balance < -1) || (node->balance > 1)) ++ node = g_tree_node_balance (node); ++ } ++ ++ return node; ++} ++ ++static GTreeNode* ++g_tree_node_remove (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key) ++{ ++ GTreeNode *new_root; ++ gint old_balance; ++ gint cmp; ++ ++ if (!node) ++ return NULL; ++ ++ cmp = (* compare) (key, node->key); ++ if (cmp == 0) ++ { ++ GTreeNode *garbage; ++ ++ garbage = node; ++ ++ if (!node->right) ++ { ++ node = node->left; ++ } ++ else ++ { ++ old_balance = node->right->balance; ++ node->right = g_tree_node_remove_leftmost (node->right, &new_root); ++ new_root->left = node->left; ++ new_root->right = node->right; ++ new_root->balance = node->balance; ++ node = g_tree_node_restore_right_balance (new_root, old_balance); ++ } ++ ++ G_LOCK (g_tree_global); ++ garbage->right = node_free_list; ++ node_free_list = garbage; ++ G_UNLOCK (g_tree_global); ++ } ++ else if (cmp < 0) ++ { ++ if (node->left) ++ { ++ old_balance = node->left->balance; ++ node->left = g_tree_node_remove (node->left, compare, key); ++ node = g_tree_node_restore_left_balance (node, old_balance); ++ } ++ } ++ else if (cmp > 0) ++ { ++ if (node->right) ++ { ++ old_balance = node->right->balance; ++ node->right = g_tree_node_remove (node->right, compare, key); ++ node = g_tree_node_restore_right_balance (node, old_balance); ++ } ++ } ++ ++ return node; ++} ++ ++static GTreeNode* ++g_tree_node_balance (GTreeNode *node) ++{ ++ if (node->balance < -1) ++ { ++ if (node->left->balance > 0) ++ node->left = g_tree_node_rotate_left (node->left); ++ node = g_tree_node_rotate_right (node); ++ } ++ else if (node->balance > 1) ++ { ++ if (node->right->balance < 0) ++ node->right = g_tree_node_rotate_right (node->right); ++ node = g_tree_node_rotate_left (node); ++ } ++ ++ return node; ++} ++ ++static GTreeNode* ++g_tree_node_remove_leftmost (GTreeNode *node, ++ GTreeNode **leftmost) ++{ ++ gint old_balance; ++ ++ if (!node->left) ++ { ++ *leftmost = node; ++ return node->right; ++ } ++ ++ old_balance = node->left->balance; ++ node->left = g_tree_node_remove_leftmost (node->left, leftmost); ++ return g_tree_node_restore_left_balance (node, old_balance); ++} ++ ++static GTreeNode* ++g_tree_node_restore_left_balance (GTreeNode *node, ++ gint old_balance) ++{ ++ if (!node->left) ++ node->balance += 1; ++ else if ((node->left->balance != old_balance) && ++ (node->left->balance == 0)) ++ node->balance += 1; ++ ++ if (node->balance > 1) ++ return g_tree_node_balance (node); ++ return node; ++} ++ ++static GTreeNode* ++g_tree_node_restore_right_balance (GTreeNode *node, ++ gint old_balance) ++{ ++ if (!node->right) ++ node->balance -= 1; ++ else if ((node->right->balance != old_balance) && ++ (node->right->balance == 0)) ++ node->balance -= 1; ++ ++ if (node->balance < -1) ++ return g_tree_node_balance (node); ++ return node; ++} ++ ++static gpointer ++g_tree_node_lookup (GTreeNode *node, ++ GCompareFunc compare, ++ gpointer key) ++{ ++ gint cmp; ++ ++ if (!node) ++ return NULL; ++ ++ cmp = (* compare) (key, node->key); ++ if (cmp == 0) ++ return node->value; ++ ++ if (cmp < 0) ++ { ++ if (node->left) ++ return g_tree_node_lookup (node->left, compare, key); ++ } ++ else if (cmp > 0) ++ { ++ if (node->right) ++ return g_tree_node_lookup (node->right, compare, key); ++ } ++ ++ return NULL; ++} ++ ++static gint ++g_tree_node_count (GTreeNode *node) ++{ ++ gint count; ++ ++ count = 1; ++ if (node->left) ++ count += g_tree_node_count (node->left); ++ if (node->right) ++ count += g_tree_node_count (node->right); ++ ++ return count; ++} ++ ++static gint ++g_tree_node_pre_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data) ++{ ++ if ((*traverse_func) (node->key, node->value, data)) ++ return TRUE; ++ if (node->left) ++ { ++ if (g_tree_node_pre_order (node->left, traverse_func, data)) ++ return TRUE; ++ } ++ if (node->right) ++ { ++ if (g_tree_node_pre_order (node->right, traverse_func, data)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static gint ++g_tree_node_in_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data) ++{ ++ if (node->left) ++ { ++ if (g_tree_node_in_order (node->left, traverse_func, data)) ++ return TRUE; ++ } ++ if ((*traverse_func) (node->key, node->value, data)) ++ return TRUE; ++ if (node->right) ++ { ++ if (g_tree_node_in_order (node->right, traverse_func, data)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static gint ++g_tree_node_post_order (GTreeNode *node, ++ GTraverseFunc traverse_func, ++ gpointer data) ++{ ++ if (node->left) ++ { ++ if (g_tree_node_post_order (node->left, traverse_func, data)) ++ return TRUE; ++ } ++ if (node->right) ++ { ++ if (g_tree_node_post_order (node->right, traverse_func, data)) ++ return TRUE; ++ } ++ if ((*traverse_func) (node->key, node->value, data)) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static gpointer ++g_tree_node_search (GTreeNode *node, ++ GSearchFunc search_func, ++ gpointer data) ++{ ++ gint dir; ++ ++ if (!node) ++ return NULL; ++ ++ do { ++ dir = (* search_func) (node->key, data); ++ if (dir == 0) ++ return node->value; ++ ++ if (dir < 0) ++ node = node->left; ++ else if (dir > 0) ++ node = node->right; ++ } while (node && (dir != 0)); ++ ++ return NULL; ++} ++ ++static gint ++g_tree_node_height (GTreeNode *node) ++{ ++ gint left_height; ++ gint right_height; ++ ++ if (node) ++ { ++ left_height = 0; ++ right_height = 0; ++ ++ if (node->left) ++ left_height = g_tree_node_height (node->left); ++ ++ if (node->right) ++ right_height = g_tree_node_height (node->right); ++ ++ return MAX (left_height, right_height) + 1; ++ } ++ ++ return 0; ++} ++ ++static GTreeNode* ++g_tree_node_rotate_left (GTreeNode *node) ++{ ++ GTreeNode *left; ++ GTreeNode *right; ++ gint a_bal; ++ gint b_bal; ++ ++ left = node->left; ++ right = node->right; ++ ++ node->right = right->left; ++ right->left = node; ++ ++ a_bal = node->balance; ++ b_bal = right->balance; ++ ++ if (b_bal <= 0) ++ { ++ if (a_bal >= 1) ++ right->balance = b_bal - 1; ++ else ++ right->balance = a_bal + b_bal - 2; ++ node->balance = a_bal - 1; ++ } ++ else ++ { ++ if (a_bal <= b_bal) ++ right->balance = a_bal - 2; ++ else ++ right->balance = b_bal - 1; ++ node->balance = a_bal - b_bal - 1; ++ } ++ ++ return right; ++} ++ ++static GTreeNode* ++g_tree_node_rotate_right (GTreeNode *node) ++{ ++ GTreeNode *left; ++ gint a_bal; ++ gint b_bal; ++ ++ left = node->left; ++ ++ node->left = left->right; ++ left->right = node; ++ ++ a_bal = node->balance; ++ b_bal = left->balance; ++ ++ if (b_bal <= 0) ++ { ++ if (b_bal > a_bal) ++ left->balance = b_bal + 1; ++ else ++ left->balance = a_bal + 2; ++ node->balance = a_bal - b_bal + 1; ++ } ++ else ++ { ++ if (a_bal <= -1) ++ left->balance = b_bal + 1; ++ else ++ left->balance = a_bal + b_bal + 2; ++ node->balance = a_bal + 1; ++ } ++ ++ return left; ++} ++ ++static void ++g_tree_node_check (GTreeNode *node) ++{ ++ gint left_height; ++ gint right_height; ++ gint balance; ++ ++ if (node) ++ { ++ left_height = 0; ++ right_height = 0; ++ ++ if (node->left) ++ left_height = g_tree_node_height (node->left); ++ if (node->right) ++ right_height = g_tree_node_height (node->right); ++ ++ balance = right_height - left_height; ++ if (balance != node->balance) ++ g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, ++ "g_tree_node_check: failed: %d ( %d )\n", ++ balance, node->balance); ++ ++ if (node->left) ++ g_tree_node_check (node->left); ++ if (node->right) ++ g_tree_node_check (node->right); ++ } ++} +diff -urN linux-2.4.1/net/korbit/kglib/gutils.c linux-2.4.1-korbit/net/korbit/kglib/gutils.c +--- linux-2.4.1/net/korbit/kglib/gutils.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/gutils.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1,915 @@ ++/* GLIB - Library of useful routines for C programming ++ * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Modified by the GLib Team and others 1997-1999. See the AUTHORS ++ * file for a list of people on the GLib Team. See the ChangeLog ++ * files for a list of changes. These files are distributed with ++ * GLib at ftp://ftp.gtk.org/pub/gtk/. ++ */ ++ ++#define G_INLINE_FUNC extern ++#define G_CAN_INLINE 1 ++ ++#ifdef HAVE_UNISTD_H ++#include <unistd.h> ++#endif ++#include <stdarg.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++#include <errno.h> ++#ifdef HAVE_PWD_H ++#include <pwd.h> ++#endif ++#include <sys/types.h> ++#ifdef HAVE_SYS_PARAM_H ++#include <sys/param.h> ++#endif ++ ++#ifdef NATIVE_WIN32 ++# define STRICT /* Strict typing, please */ ++# include <windows.h> ++# include <direct.h> ++# include <errno.h> ++# include <ctype.h> ++# ifdef _MSC_VER ++# include <io.h> ++# endif /* _MSC_VER */ ++#endif /* NATIVE_WIN32 */ ++ ++/* implement Glib's inline functions ++ */ ++#include "glib.h" ++ ++#ifdef MAXPATHLEN ++#define G_PATH_LENGTH (MAXPATHLEN + 1) ++#elif defined (PATH_MAX) ++#define G_PATH_LENGTH (PATH_MAX + 1) ++#else /* !MAXPATHLEN */ ++#define G_PATH_LENGTH (2048 + 1) ++#endif /* !MAXPATHLEN && !PATH_MAX */ ++ ++const guint glib_major_version = 1; ++const guint glib_minor_version = 2; ++const guint glib_micro_version = 8; ++const guint glib_interface_age = 8; ++const guint glib_binary_age = 8; ++ ++#if defined (NATIVE_WIN32) && defined (__LCC__) ++int __stdcall ++LibMain (void *hinstDll, ++ unsigned long dwReason, ++ void *reserved) ++{ ++ return 1; ++} ++#endif /* NATIVE_WIN32 && __LCC__ */ ++ ++void ++g_atexit (GVoidFunc func) ++{ ++ gint result; ++ gchar *error = NULL; ++ ++ /* keep this in sync with glib.h */ ++ ++#ifdef G_NATIVE_ATEXIT ++ result = ATEXIT (func); ++ if (result) ++ error = g_strerror (errno); ++#elif defined (HAVE_ATEXIT) ++# ifdef NeXT /* @#%@! NeXTStep */ ++ result = !atexit ((void (*)(void)) func); ++ if (result) ++ error = g_strerror (errno); ++# else ++ result = atexit ((void (*)(void)) func); ++ if (result) ++ error = g_strerror (errno); ++# endif /* NeXT */ ++#elif defined (HAVE_ON_EXIT) ++ result = on_exit ((void (*)(int, void *)) func, NULL); ++ if (result) ++ error = g_strerror (errno); ++#else ++ result = 0; ++ error = "no implementation"; ++#endif /* G_NATIVE_ATEXIT */ ++ ++ if (error) ++ g_error ("Could not register atexit() function: %s", error); ++} ++ ++gint ++g_snprintf (gchar *str, ++ gulong n, ++ gchar const *fmt, ++ ...) ++{ ++#ifdef HAVE_VSNPRINTF ++ va_list args; ++ gint retval; ++ ++ g_return_val_if_fail (str != NULL, 0); ++ g_return_val_if_fail (n > 0, 0); ++ g_return_val_if_fail (fmt != NULL, 0); ++ ++ va_start (args, fmt); ++ retval = vsnprintf (str, n, fmt, args); ++ va_end (args); ++ ++ if (retval < 0) ++ { ++ str[n-1] = '\0'; ++ retval = strlen (str); ++ } ++ ++ return retval; ++#else /* !HAVE_VSNPRINTF */ ++ gchar *printed; ++ va_list args; ++ ++ g_return_val_if_fail (str != NULL, 0); ++ g_return_val_if_fail (n > 0, 0); ++ g_return_val_if_fail (fmt != NULL, 0); ++ ++ va_start (args, fmt); ++ printed = g_strdup_vprintf (fmt, args); ++ va_end (args); ++ ++ strncpy (str, printed, n); ++ str[n-1] = '\0'; ++ ++ g_free (printed); ++ ++ return strlen (str); ++#endif /* !HAVE_VSNPRINTF */ ++} ++ ++gint ++g_vsnprintf (gchar *str, ++ gulong n, ++ gchar const *fmt, ++ va_list args) ++{ ++#ifdef HAVE_VSNPRINTF ++ gint retval; ++ ++ g_return_val_if_fail (str != NULL, 0); ++ g_return_val_if_fail (n > 0, 0); ++ g_return_val_if_fail (fmt != NULL, 0); ++ ++ retval = vsnprintf (str, n, fmt, args); ++ ++ if (retval < 0) ++ { ++ str[n-1] = '\0'; ++ retval = strlen (str); ++ } ++ ++ return retval; ++#else /* !HAVE_VSNPRINTF */ ++ gchar *printed; ++ ++ g_return_val_if_fail (str != NULL, 0); ++ g_return_val_if_fail (n > 0, 0); ++ g_return_val_if_fail (fmt != NULL, 0); ++ ++ printed = g_strdup_vprintf (fmt, args); ++ strncpy (str, printed, n); ++ str[n-1] = '\0'; ++ ++ g_free (printed); ++ ++ return strlen (str); ++#endif /* !HAVE_VSNPRINTF */ ++} ++ ++guint ++g_parse_debug_string (const gchar *string, ++ GDebugKey *keys, ++ guint nkeys) ++{ ++ guint i; ++ guint result = 0; ++ ++ g_return_val_if_fail (string != NULL, 0); ++ ++ if (!g_strcasecmp (string, "all")) ++ { ++ for (i=0; i<nkeys; i++) ++ result |= keys[i].value; ++ } ++ else ++ { ++ gchar *str = g_strdup (string); ++ gchar *p = str; ++ gchar *q; ++ gboolean done = FALSE; ++ ++ while (*p && !done) ++ { ++ q = strchr (p, ':'); ++ if (!q) ++ { ++ q = p + strlen(p); ++ done = TRUE; ++ } ++ ++ *q = 0; ++ ++ for (i=0; i<nkeys; i++) ++ if (!g_strcasecmp(keys[i].key, p)) ++ result |= keys[i].value; ++ ++ p = q+1; ++ } ++ ++ g_free (str); ++ } ++ ++ return result; ++} ++ ++gchar* ++g_basename (const gchar *file_name) ++{ ++ register gchar *base; ++ ++ g_return_val_if_fail (file_name != NULL, NULL); ++ ++ base = strrchr (file_name, G_DIR_SEPARATOR); ++ if (base) ++ return base + 1; ++ ++#ifdef NATIVE_WIN32 ++ if (isalpha (file_name[0]) && file_name[1] == ':') ++ return (gchar*) file_name + 2; ++#endif /* NATIVE_WIN32 */ ++ ++ return (gchar*) file_name; ++} ++ ++gboolean ++g_path_is_absolute (const gchar *file_name) ++{ ++ g_return_val_if_fail (file_name != NULL, FALSE); ++ ++ if (file_name[0] == G_DIR_SEPARATOR) ++ return TRUE; ++ ++#ifdef NATIVE_WIN32 ++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR) ++ return TRUE; ++#endif ++ ++ return FALSE; ++} ++ ++gchar* ++g_path_skip_root (gchar *file_name) ++{ ++ g_return_val_if_fail (file_name != NULL, NULL); ++ ++ if (file_name[0] == G_DIR_SEPARATOR) ++ return file_name + 1; ++ ++#ifdef NATIVE_WIN32 ++ if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR) ++ return file_name + 3; ++#endif ++ ++ return NULL; ++} ++ ++gchar* ++g_dirname (const gchar *file_name) ++{ ++ register gchar *base; ++ register guint len; ++ ++ g_return_val_if_fail (file_name != NULL, NULL); ++ ++ base = strrchr (file_name, G_DIR_SEPARATOR); ++ if (!base) ++ return g_strdup ("."); ++ while (base > file_name && *base == G_DIR_SEPARATOR) ++ base--; ++ len = (guint) 1 + base - file_name; ++ ++ base = g_new (gchar, len + 1); ++ g_memmove (base, file_name, len); ++ base[len] = 0; ++ ++ return base; ++} ++ ++#ifndef __KORBIT__ ++gchar* ++g_get_current_dir (void) ++{ ++ gchar *buffer; ++ gchar *dir; ++ ++ buffer = g_new (gchar, G_PATH_LENGTH); ++ *buffer = 0; ++ ++ /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd") ++ * and, if that wasn't bad enough, hangs in doing so. ++ */ ++#if defined (sun) && !defined (__SVR4) ++ dir = getwd (buffer); ++#else /* !sun */ ++ dir = getcwd (buffer, G_PATH_LENGTH - 1); ++#endif /* !sun */ ++ ++ if (!dir || !*buffer) ++ { ++ /* hm, should we g_error() out here? ++ * this can happen if e.g. "./" has mode \0000 ++ */ ++ buffer[0] = G_DIR_SEPARATOR; ++ buffer[1] = 0; ++ } ++ ++ dir = g_strdup (buffer); ++ g_free (buffer); ++ ++ return dir; ++} ++#endif /* !__KORBIT__ */ ++ ++gchar* ++g_getenv (const gchar *variable) ++{ ++#ifndef NATIVE_WIN32 ++ g_return_val_if_fail (variable != NULL, NULL); ++ ++ return getenv (variable); ++#else ++ gchar *v; ++ guint k; ++ static gchar *p = NULL; ++ static gint l; ++ gchar dummy[2]; ++ ++ g_return_val_if_fail (variable != NULL, NULL); ++ ++ v = getenv (variable); ++ if (!v) ++ return NULL; ++ ++ /* On Windows NT, it is relatively typical that environment variables ++ * contain references to other environment variables. Handle that by ++ * calling ExpandEnvironmentStrings. ++ */ ++ ++ /* First check how much space we need */ ++ k = ExpandEnvironmentStrings (v, dummy, 2); ++ /* Then allocate that much, and actualy do the expansion */ ++ if (p == NULL) ++ { ++ p = g_malloc (k); ++ l = k; ++ } ++ else if (k > l) ++ { ++ p = g_realloc (p, k); ++ l = k; ++ } ++ ExpandEnvironmentStrings (v, p, k); ++ return p; ++#endif ++} ++ ++ ++G_LOCK_DEFINE_STATIC (g_utils_global); ++ ++static gchar *g_tmp_dir = NULL; ++static gchar *g_user_name = NULL; ++static gchar *g_real_name = NULL; ++static gchar *g_home_dir = NULL; ++ ++/* HOLDS: g_utils_global_lock */ ++static void ++g_get_any_init (void) ++{ ++ if (!g_tmp_dir) ++ { ++ g_tmp_dir = g_strdup (g_getenv ("TMPDIR")); ++ if (!g_tmp_dir) ++ g_tmp_dir = g_strdup (g_getenv ("TMP")); ++ if (!g_tmp_dir) ++ g_tmp_dir = g_strdup (g_getenv ("TEMP")); ++ ++#ifdef P_tmpdir ++ if (!g_tmp_dir) ++ { ++ int k; ++ g_tmp_dir = g_strdup (P_tmpdir); ++ k = strlen (g_tmp_dir); ++ if (g_tmp_dir[k-1] == G_DIR_SEPARATOR) ++ g_tmp_dir[k-1] = '\0'; ++ } ++#endif ++ ++ if (!g_tmp_dir) ++ { ++#ifndef NATIVE_WIN32 ++ g_tmp_dir = g_strdup ("/tmp"); ++#else /* NATIVE_WIN32 */ ++ g_tmp_dir = g_strdup ("C:\\"); ++#endif /* NATIVE_WIN32 */ ++ } ++ ++ if (!g_home_dir) ++ g_home_dir = g_strdup (g_getenv ("HOME")); ++ ++#ifdef NATIVE_WIN32 ++ if (!g_home_dir) ++ { ++ /* The official way to specify a home directory on NT is ++ * the HOMEDRIVE and HOMEPATH environment variables. ++ * ++ * This is inside #ifdef NATIVE_WIN32 because with the cygwin dll, ++ * HOME should be a POSIX style pathname. ++ */ ++ ++ if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL) ++ { ++ gchar *homedrive, *homepath; ++ ++ homedrive = g_strdup (g_getenv ("HOMEDRIVE")); ++ homepath = g_strdup (g_getenv ("HOMEPATH")); ++ ++ g_home_dir = g_strconcat (homedrive, homepath, NULL); ++ g_free (homedrive); ++ g_free (homepath); ++ } ++ } ++#endif /* !NATIVE_WIN32 */ ++ ++#ifdef HAVE_PWD_H ++ { ++ struct passwd *pw = NULL; ++ gpointer buffer = NULL; ++ ++# ifdef HAVE_GETPWUID_R ++ struct passwd pwd; ++ guint bufsize = 64; ++ gint error; ++ ++ do ++ { ++ g_free (buffer); ++ buffer = g_malloc (bufsize); ++ errno = 0; ++ ++# ifdef HAVE_GETPWUID_R_POSIX ++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw); ++ error = error < 0 ? errno : error; ++# else /* !HAVE_GETPWUID_R_POSIX */ ++# ifdef _AIX ++ error = getpwuid_r (getuid (), &pwd, buffer, bufsize); ++ pw = error == 0 ? &pwd : NULL; ++# else /* !_AIX */ ++ pw = getpwuid_r (getuid (), &pwd, buffer, bufsize); ++ error = pw ? 0 : errno; ++# endif /* !_AIX */ ++# endif /* !HAVE_GETPWUID_R_POSIX */ ++ ++ if (!pw) ++ { ++ /* we bail out prematurely if the user id can't be found ++ * (should be pretty rare case actually), or if the buffer ++ * should be sufficiently big and lookups are still not ++ * successfull. ++ */ ++ if (error == 0 || error == ENOENT) ++ { ++ g_warning ("getpwuid_r(): failed due to: No such user %d.", ++ getuid ()); ++ break; ++ } ++ if (bufsize > 32 * 1024) ++ { ++ g_warning ("getpwuid_r(): failed due to: %s.", ++ g_strerror (error)); ++ break; ++ } ++ ++ bufsize *= 2; ++ } ++ } ++ while (!pw); ++# endif /* !HAVE_GETPWUID_R */ ++ ++ if (!pw) ++ { ++ setpwent (); ++ pw = getpwuid (getuid ()); ++ endpwent (); ++ } ++ if (pw) ++ { ++ g_user_name = g_strdup (pw->pw_name); ++ g_real_name = g_strdup (pw->pw_gecos); ++ if (!g_home_dir) ++ g_home_dir = g_strdup (pw->pw_dir); ++ } ++ g_free (buffer); ++ } ++ ++#else /* !HAVE_PWD_H */ ++ ++# ifdef NATIVE_WIN32 ++ { ++ guint len = 17; ++ gchar buffer[17]; ++ ++ if (GetUserName (buffer, &len)) ++ { ++ g_user_name = g_strdup (buffer); ++ g_real_name = g_strdup (buffer); ++ } ++ } ++# endif /* NATIVE_WIN32 */ ++ ++#endif /* !HAVE_PWD_H */ ++ ++ if (!g_user_name) ++ g_user_name = g_strdup ("somebody"); ++ if (!g_real_name) ++ g_real_name = g_strdup ("Unknown"); ++ else ++ { ++ gchar *p; ++ ++ for (p = g_real_name; *p; p++) ++ if (*p == ',') ++ { ++ *p = 0; ++ p = g_strdup (g_real_name); ++ g_free (g_real_name); ++ g_real_name = p; ++ break; ++ } ++ } ++ } ++} ++ ++gchar* ++g_get_user_name (void) ++{ ++ G_LOCK (g_utils_global); ++ if (!g_tmp_dir) ++ g_get_any_init (); ++ G_UNLOCK (g_utils_global); ++ ++ return g_user_name; ++} ++ ++gchar* ++g_get_real_name (void) ++{ ++ G_LOCK (g_utils_global); ++ if (!g_tmp_dir) ++ g_get_any_init (); ++ G_UNLOCK (g_utils_global); ++ ++ return g_real_name; ++} ++ ++/* Return the home directory of the user. If there is a HOME ++ * environment variable, its value is returned, otherwise use some ++ * system-dependent way of finding it out. If no home directory can be ++ * deduced, return NULL. ++ */ ++ ++gchar* ++g_get_home_dir (void) ++{ ++ G_LOCK (g_utils_global); ++ if (!g_tmp_dir) ++ g_get_any_init (); ++ G_UNLOCK (g_utils_global); ++ ++ return g_home_dir; ++} ++ ++/* Return a directory to be used to store temporary files. This is the ++ * value of the TMPDIR, TMP or TEMP environment variables (they are ++ * checked in that order). If none of those exist, use P_tmpdir from ++ * stdio.h. If that isn't defined, return "/tmp" on POSIXly systems, ++ * and C:\ on Windows. ++ */ ++ ++gchar* ++g_get_tmp_dir (void) ++{ ++ G_LOCK (g_utils_global); ++ if (!g_tmp_dir) ++ g_get_any_init (); ++ G_UNLOCK (g_utils_global); ++ ++ return g_tmp_dir; ++} ++ ++static gchar *g_prgname = NULL; ++ ++gchar* ++g_get_prgname (void) ++{ ++ gchar* retval; ++ ++ G_LOCK (g_utils_global); ++ retval = g_prgname; ++ G_UNLOCK (g_utils_global); ++ ++ return retval; ++} ++ ++void ++g_set_prgname (const gchar *prgname) ++{ ++ gchar *c; ++ ++ G_LOCK (g_utils_global); ++ c = g_prgname; ++ g_prgname = g_strdup (prgname); ++ g_free (c); ++ G_UNLOCK (g_utils_global); ++} ++ ++guint ++g_direct_hash (gconstpointer v) ++{ ++ return GPOINTER_TO_UINT (v); ++} ++ ++gint ++g_direct_equal (gconstpointer v1, ++ gconstpointer v2) ++{ ++ return v1 == v2; ++} ++ ++gint ++g_int_equal (gconstpointer v1, ++ gconstpointer v2) ++{ ++ return *((const gint*) v1) == *((const gint*) v2); ++} ++ ++guint ++g_int_hash (gconstpointer v) ++{ ++ return *(const gint*) v; ++} ++ ++#if 0 /* Old IO Channels */ ++ ++GIOChannel* ++g_iochannel_new (gint fd) ++{ ++ GIOChannel *channel = g_new (GIOChannel, 1); ++ ++ channel->fd = fd; ++ ++#ifdef NATIVE_WIN32 ++ channel->peer = 0; ++ channel->peer_fd = 0; ++ channel->offset = 0; ++ channel->need_wakeups = 0; ++#endif /* NATIVE_WIN32 */ ++ ++ return channel; ++} ++ ++void ++g_iochannel_free (GIOChannel *channel) ++{ ++ g_return_if_fail (channel != NULL); ++ ++ g_free (channel); ++} ++ ++void ++g_iochannel_close_and_free (GIOChannel *channel) ++{ ++ g_return_if_fail (channel != NULL); ++ ++ close (channel->fd); ++ ++ g_iochannel_free (channel); ++} ++ ++#undef g_iochannel_wakeup_peer ++ ++void ++g_iochannel_wakeup_peer (GIOChannel *channel) ++{ ++#ifdef NATIVE_WIN32 ++ static guint message = 0; ++#endif ++ ++ g_return_if_fail (channel != NULL); ++ ++#ifdef NATIVE_WIN32 ++ if (message == 0) ++ message = RegisterWindowMessage ("gdk-pipe-readable"); ++ ++# if 0 ++ g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n", ++ channel->peer, message, channel->peer_fd, channel->offset); ++# endif ++ PostThreadMessage (channel->peer, message, ++ channel->peer_fd, channel->offset); ++#endif /* NATIVE_WIN32 */ ++} ++ ++#endif /* Old IO Channels */ ++ ++#ifdef NATIVE_WIN32 ++#ifdef _MSC_VER ++ ++int ++gwin_ftruncate (gint fd, ++ guint size) ++{ ++ HANDLE hfile; ++ guint curpos; ++ ++ g_return_val_if_fail (fd >= 0, -1); ++ ++ hfile = (HANDLE) _get_osfhandle (fd); ++ curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT); ++ if (curpos == 0xFFFFFFFF ++ || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF ++ || !SetEndOfFile (hfile)) ++ { ++ gint error = GetLastError (); ++ ++ switch (error) ++ { ++ case ERROR_INVALID_HANDLE: ++ errno = EBADF; ++ break; ++ default: ++ errno = EIO; ++ break; ++ } ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ ++DIR* ++gwin_opendir (const char *dirname) ++{ ++ DIR *result; ++ gchar *mask; ++ guint k; ++ ++ g_return_val_if_fail (dirname != NULL, NULL); ++ ++ result = g_new0 (DIR, 1); ++ result->find_file_data = g_new0 (WIN32_FIND_DATA, 1); ++ result->dir_name = g_strdup (dirname); ++ ++ k = strlen (result->dir_name); ++ if (k && result->dir_name[k - 1] == '\\') ++ { ++ result->dir_name[k - 1] = '\0'; ++ k--; ++ } ++ mask = g_strdup_printf ("%s\\*", result->dir_name); ++ ++ result->find_file_handle = (guint) FindFirstFile (mask, ++ (LPWIN32_FIND_DATA) result->find_file_data); ++ g_free (mask); ++ ++ if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE) ++ { ++ int error = GetLastError (); ++ ++ g_free (result->dir_name); ++ g_free (result->find_file_data); ++ g_free (result); ++ switch (error) ++ { ++ default: ++ errno = EIO; ++ return NULL; ++ } ++ } ++ result->just_opened = TRUE; ++ ++ return result; ++} ++ ++struct dirent* ++gwin_readdir (DIR *dir) ++{ ++ static struct dirent result; ++ ++ g_return_val_if_fail (dir != NULL, NULL); ++ ++ if (dir->just_opened) ++ dir->just_opened = FALSE; ++ else ++ { ++ if (!FindNextFile ((HANDLE) dir->find_file_handle, ++ (LPWIN32_FIND_DATA) dir->find_file_data)) ++ { ++ int error = GetLastError (); ++ ++ switch (error) ++ { ++ case ERROR_NO_MORE_FILES: ++ return NULL; ++ default: ++ errno = EIO; ++ return NULL; ++ } ++ } ++ } ++ strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName)); ++ ++ return &result; ++} ++ ++void ++gwin_rewinddir (DIR *dir) ++{ ++ gchar *mask; ++ ++ g_return_if_fail (dir != NULL); ++ ++ if (!FindClose ((HANDLE) dir->find_file_handle)) ++ g_warning ("gwin_rewinddir(): FindClose() failed\n"); ++ ++ mask = g_strdup_printf ("%s\\*", dir->dir_name); ++ dir->find_file_handle = (guint) FindFirstFile (mask, ++ (LPWIN32_FIND_DATA) dir->find_file_data); ++ g_free (mask); ++ ++ if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE) ++ { ++ int error = GetLastError (); ++ ++ switch (error) ++ { ++ default: ++ errno = EIO; ++ return; ++ } ++ } ++ dir->just_opened = TRUE; ++} ++ ++gint ++gwin_closedir (DIR *dir) ++{ ++ g_return_val_if_fail (dir != NULL, -1); ++ ++ if (!FindClose ((HANDLE) dir->find_file_handle)) ++ { ++ int error = GetLastError (); ++ ++ switch (error) ++ { ++ default: ++ errno = EIO; return -1; ++ } ++ } ++ ++ g_free (dir->dir_name); ++ g_free (dir->find_file_data); ++ g_free (dir); ++ ++ return 0; ++} ++ ++#endif /* _MSC_VER */ ++ ++#endif /* NATIVE_WIN32 */ +diff -urN linux-2.4.1/net/korbit/kglib/korbit_errno.c linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c +--- linux-2.4.1/net/korbit/kglib/korbit_errno.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/kglib/korbit_errno.c Thu Feb 1 11:46:57 2001 +@@ -0,0 +1 @@ ++int korbit_errno; +diff -urN linux-2.4.1/net/korbit/korbit.h linux-2.4.1-korbit/net/korbit/korbit.h +--- linux-2.4.1/net/korbit/korbit.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/korbit.h Thu Feb 1 11:46:49 2001 +@@ -0,0 +1,53 @@ ++ ++#ifndef KORBIT_H ++#define KORBIT_H ++ ++#ifdef __KERNEL__ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#endif ++ ++#include "stdlib.h" ++ ++#ifdef __KERNEL__ ++static int korbit_get_ior_func(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) { ++ int Len = strlen((char*)data); ++ memcpy(buffer, data, Len); // Data is the ior... ++ buffer[Len++] = '\n'; // Add a newline to make fredrik happy ++ buffer[Len] = 0; // Null terminate the buffer... ++ *start = buffer + offset; ++ *eof = 1; ++ ++ Len -= offset; ++ if (Len > length) ++ Len = length; ++ if (Len < 0) ++ Len = 0; ++ ++ return Len; ++} ++ ++#endif ++ ++ ++static inline void korbit_register_ior(const char *name, CORBA_Object obj, ++ CORBA_ORB orb, CORBA_Environment *ev) { ++ char *retval = CORBA_ORB_object_to_string(orb, obj, ev); ++#if defined(__KERNEL__) && defined(CONFIG_PROC_FS) ++ char *procdirname = malloc(strlen(name)+7); // 7 = len("corba/\0") ++ strcpy(procdirname, "corba/"); ++ strcpy(procdirname+6, name); ++ ++ create_proc_read_entry(procdirname, 0, 0, korbit_get_ior_func, retval); ++ ++ free(procdirname); ++ // Don't free the ior in the /proc handling case... ++#else ++ // No procfs support, just print to console... :( ++ g_print("%s IOR:\n%s\n", name, retval); ++ CORBA_free(retval); ++#endif ++} ++#endif +diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,5 @@ ++/Config.in/1.8/Thu Feb 1 09:46:58 2001// ++/Makefile/1.8/Thu Feb 1 09:46:58 2001// ++/Makefile.module/1.2/Thu Feb 1 09:46:58 2001// ++/README/1.1/Thu Feb 1 09:46:58 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Entries.Log Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,6 @@ ++A D/CharDev//// ++A D/Console//// ++A D/CorbaFS//// ++A D/Echo//// ++A D/FileServer//// ++A D/UserFS//// +diff -urN linux-2.4.1/net/korbit/modules/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Repository Thu Feb 1 11:46:57 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules +diff -urN linux-2.4.1/net/korbit/modules/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CVS/Root +--- linux-2.4.1/net/korbit/modules/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CVS/Root Thu Feb 1 11:46:57 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,4 @@ ++/Makefile/1.3/Thu Feb 1 09:46:58 2001// ++/README/1.1/Thu Feb 1 09:46:58 2001// ++/chardev.idl/1.1/Thu Feb 1 09:46:58 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Entries.Log Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,3 @@ ++A D/kernel//// ++A D/kernel-perl//// ++A D/userspace//// +diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Repository Thu Feb 1 11:46:58 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CharDev +diff -urN linux-2.4.1/net/korbit/modules/CharDev/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root +--- linux-2.4.1/net/korbit/modules/CharDev/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/CVS/Root Thu Feb 1 11:46:58 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CharDev/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile +--- linux-2.4.1/net/korbit/modules/CharDev/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/Makefile Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,11 @@ ++# ++# Makefile for KORBit - CharDev ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_CHARDEV) := kernel ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/CharDev/README linux-2.4.1-korbit/net/korbit/modules/CharDev/README +--- linux-2.4.1/net/korbit/modules/CharDev/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/README Thu Feb 1 11:46:58 2001 +@@ -0,0 +1 @@ ++This module is used to implement a character device with kORBit. +diff -urN linux-2.4.1/net/korbit/modules/CharDev/chardev.idl linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl +--- linux-2.4.1/net/korbit/modules/CharDev/chardev.idl Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/chardev.idl Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,5 @@ ++typedef sequence<octet> Buffer; ++ ++interface CharDev { ++ long read(out Buffer buffer, in long size); ++}; +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Entries Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,4 @@ ++/Makefile/1.2/Thu Feb 1 09:46:59 2001// ++/README/1.2/Thu Feb 1 09:46:59 2001// ++/chardev-kernel.c/1.9/Thu Feb 1 09:46:59 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Repository Thu Feb 1 11:46:59 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/CVS/Root Thu Feb 1 11:46:59 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/Makefile Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,20 @@ ++# ++# Makefile for KORBit / chardev ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-chardev-kernel.o ++ ++obj-y := chardev-common.o chardev-stubs.o chardev-kernel.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++chardev-kernel.c: chardev.h ++ ++chardev.h chardev-stubs.c chardev-common.c: ../chardev.idl ++ $(ORBIT_IDL) ../chardev.idl +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/README Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,5 @@ ++This module is used to implement the kernel side of the CORBA Character ++device. ++ ++ORB: kORBit ++Status: Working!!! +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c +--- linux-2.4.1/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel/chardev-kernel.c Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,140 @@ ++//----------------------------------------------------------------------------- ++// ++// chardev-kernel - Kernel miscdevice to CORBA glue. ++// ++// This file implements a standard Linux Kernel "miscdevice". This device ++// operates by forwarding all calls across to a remote CORBA server. This ++// server is located by reading the file /tmp/chardev-ior at the time the ++// device is opened. The device exported is major #10, minor #42. Create this ++// device with 'mknod' like all the others. ++// ++// No implementations of CORBA functions should block, although I think it ++// might be just fine, I'm not sure. Let's just make this a TODO. :) -CAL ++// ++// TODO: Locking, finish exporting all "miscdevice" functions, send position ++// on READ request. ++// ++// History: ++// Keith Wessel - Initial hack, initial idea ++// Andy Reitz - Get it to compile ++// Chris Lattner - Make it work. :) ++// ++//----------------------------------------------------------------------------- ++ ++ ++#include "chardev.h" ++#include <stdio.h> ++#include "orb/orbit.h" ++#include "korbit.h" ++#include <linux/miscdevice.h> ++ ++#define DEV_MINOR 42 ++ ++CORBA_ORB orb; ++CORBA_Environment *ev; ++ ++static int open_dev(struct inode *inode, struct file *file) { ++ char *iorstr = (char *)malloc(10240); ++ int error = -EINVAL; ++ int fd, len; ++ ++ if (iorstr == 0) return -ENOMEM; ++ ++ if ((fd = open ("/tmp/chardev-ior", O_RDONLY, 0)) == -1) { ++ printk("kORBit: chararacter driver couldn't open /tmp/chardev-ior!\n"); ++ goto outfree; ++ } ++ ++ len = read(fd, iorstr, 10240); ++ close(fd); ++ if (len == -1) ++ goto outfree; ++ ++ iorstr[len] = 0; // Null terminate string! ++ ++ printk("CharDEV IOR String = %s\n", iorstr); ++ file->private_data = (void*)CORBA_ORB_string_to_object(orb, iorstr, ev); ++ if (!file->private_data) ++ goto outfree; ++ ++ // TODO: Send create_dev message out over CORBA ++ ++ error = 0; ++ outfree: ++ free(iorstr); ++ return error; ++} ++ ++static int release_dev(struct inode *inode, struct file *file) { ++ // TODO: Send release_dev message out over CORBA... ++ if (file->private_data) ++ CORBA_free(file->private_data); ++ return 0; ++} ++ ++ ++static ssize_t read_dev(struct file * file, char * buf, size_t count, ++ loff_t *ppos) { ++ Buffer *octet_buffer = NULL; ++ if (!file->private_data) return -EINVAL; ++ if (!count) return 0; ++ ++ if (!access_ok(VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ CharDev_read(file->private_data, &octet_buffer, count, ev); ++ ++ if (!octet_buffer) ++ return -EPERM; ++ ++ if (copy_to_user(buf, octet_buffer->_buffer, octet_buffer->_length)) ++ return -EFAULT; ++ ++ // TODO: Should free octet_buffer here!?!?!? ++ ++ return octet_buffer->_length; ++} ++ ++ ++//----------------------------------------------------------------------------- ++// Kernel Callbacks for miscdevice ++//----------------------------------------------------------------------------- ++ ++ ++static struct file_operations dev_fops = { ++ owner: THIS_MODULE, ++ open: open_dev, ++ read: read_dev, ++ release: release_dev, ++ // mmap: mmap_dev, ++ // llseek: llseek_dev, ++ // write: write_dev, ++}; ++ ++static struct miscdevice cdev = { ++ DEV_MINOR, ++ "CORBA Character device", ++ &dev_fops ++}; ++ ++ ++//----------------------------------------------------------------------------- ++// Module Initializion/Finalization ++//----------------------------------------------------------------------------- ++ ++static int __init CharDev_init(void) { ++ int argc = 1; ++ char *argv[] = { "CharDev-kernel", 0 }; ++ ev = g_new0(CORBA_Environment,1); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ ++ // Register the device ++ return misc_register(&cdev); ++} ++ ++static void __exit CharDev_exit(void) { ++ misc_deregister(&cdev); ++} ++ ++module_init(CharDev_init) ++module_exit(CharDev_exit) +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Entries Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,3 @@ ++/PerlTest/1.1/Thu Feb 1 09:46:59 2001// ++/README/1.1/Thu Feb 1 09:46:59 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Repository Thu Feb 1 11:46:59 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CharDev/kernel-perl +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root +--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/CVS/Root Thu Feb 1 11:46:59 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest +--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/PerlTest Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,17 @@ ++#!/usr/bin/perl -w ++ ++use CORBA::ORBit idl => [ qw(../chardev.idl) ]; ++use Error qw(:try); ++use strict; ++ ++my $orb = CORBA::ORB_init("orbit-local-orb"); ++open IOR, "/tmp/chardev-ior" or die "no chardev server found!"; ++my $ior = <IOR>; ++close IOR; ++#chomp($ior); # Kill fredrik's newline... ++ ++my $chardev = $orb->string_to_object($ior); ++# Echo echoString(in string astring, out long anum); ++my ($ressize, $buf) = $chardev->read(10); ++ ++print "Return size = $ressize\nresult = $buf\n"; +diff -urN linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README +--- linux-2.4.1/net/korbit/modules/CharDev/kernel-perl/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/kernel-perl/README Thu Feb 1 11:46:59 2001 +@@ -0,0 +1,6 @@ ++This module is used to test the user side of the CORBA Character ++device. It doesn't do anything really complex, just implements a quick ++sanity test for the server. ++ ++ORB: ORBit - Perl ++Status: Working! +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Entries Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,6 @@ ++/Makefile/1.5/Thu Feb 1 09:47:00 2001// ++/README/1.1/Thu Feb 1 09:47:00 2001// ++/RunServer.sh/1.1/Thu Feb 1 09:47:00 2001// ++/chardev-server.c/1.5/Thu Feb 1 09:47:00 2001// ++/chardev-skelimpl.c/1.5/Thu Feb 1 09:47:00 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Repository Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CharDev/userspace +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/CVS/Root Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/Makefile Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,30 @@ ++# ++# Makefile for KORBit / CharDev ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++CFLAGS = -Wall -I/usr/lib/glib/include ++LDFLAGS = -lORBit -lIIOP -lORBitutil ++OBJS = chardev-common.o chardev-skels.o chardev-server.o ++ORBIT-IDL = /usr/bin/orbit-idl ++ ++chardev-server: $(OBJS) ++ gcc -o chardev-server $(OBJS) $(LDFLAGS) ++ ++chardev-server.o: chardev.h chardev-skelimpl.c ++ ++chardev.h chardev-skels.c chardev-common.c: ../chardev.idl ++ $(ORBIT-IDL) ../chardev.idl ++ ++chardev-skelimpl.c: ++ ++%.o: %.c ++ gcc -c $< $(CFLAGS) ++clean: ++ rm -f $(OBJS) chardev-server chardev-common.c chardev-skels.c \ ++ chardev-stubs.c chardev.h ++ +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/README linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/README Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,4 @@ ++This is an example character driver. ++ ++ORB: ORBit ++Status: not yet working +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/RunServer.sh Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++./chardev-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1 +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-server.c Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,77 @@ ++//----------------------------------------------------------------------------- ++// ++// chardev-server.c - TEST Kernel miscdevice implementation ++// ++// This file implements the standard server code for a userspace server. This ++// is basically cut and paste boilerplate code adapted from the CorbaFS server ++// by Fredrik Vraalsen. ++// ++// TODO: Locking, finish exporting all "miscdevice" functions, send position ++// on READ request. ++// ++// History: ++// Keith Wessel - Initial hack, initial idea ++// Andy Reitz - Get it to compile ++// Chris Lattner - Hack'n'slash, make it work, comment it, kill warnings. ++// ++//----------------------------------------------------------------------------- ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <signal.h> ++#include <orb/orbit.h> ++ ++// #include the C file because all the functions are static. Bizarre. ++#include "chardev-skelimpl.c" ++ ++int main(int argc, char *argv[]) { ++ PortableServer_POA poa; ++ PortableServer_POAManager pm; ++ ++ CharDev chardev = CORBA_OBJECT_NIL; ++ impl_POA_CharDev *chardev_impl; ++ PortableServer_ObjectId *objid; ++ ++ CORBA_Environment ev; ++ char *retval; ++ CORBA_ORB orb; ++ FILE *IORFILE; ++ ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); ++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", &ev); ++ ++ chardev = impl_CharDev__create(poa, &ev); ++ pm = PortableServer_POA__get_the_POAManager(poa, &ev); ++ PortableServer_POAManager_activate(pm, &ev); ++ ++ if (!chardev) { ++ printf("Cannot get objref\n"); ++ return 1; ++ } ++ ++ chardev_impl = PortableServer_POA_reference_to_servant(poa, chardev, &ev); ++ objid = PortableServer_POA_servant_to_id(poa, chardev_impl, &ev); ++ ++ retval = CORBA_ORB_object_to_string(orb, chardev, &ev); ++ ++ g_print("FYI, this also goes into /tmp/chardev-ior for you.\n"); ++ g_print("%s\n", retval); fflush(stdout); ++ ++ IORFILE = fopen ("/tmp/chardev-ior", "w"); ++ if (IORFILE == NULL) { ++ perror("ERROR: IOR_WRITE_TO_DISK"); ++ exit(1); ++ } ++ ++ fprintf(IORFILE, "%s", retval); ++ fclose(IORFILE); ++ ++ CORBA_free(retval); // Free the corba string like a good little CORBear ++ ++ ++ // La dee dah... I will never return for you mister. ++ CORBA_ORB_run(orb, &ev); ++ return 0; ++} ++ +diff -urN linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c +--- linux-2.4.1/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CharDev/userspace/chardev-skelimpl.c Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,119 @@ ++//----------------------------------------------------------------------------- ++// ++// chardev-skelimpl.c - TEST Kernel miscdevice implementation ++// ++// This file implements a CORBA "miscdevice" (character device node). ++// This device simply outputs a fixed string (set by "message", below) when ++// cat'd. Pretty simple stuff, but you can obviously do much more creative ++// things with it. ++// ++// TODO: Locking, finish exporting all "miscdevice" functions, send position ++// on READ request. ++// ++// Right now we have ONE server object with global state, so that when you ++// read the string from that object, it is finished. This should be reset ++// whenever an open request is had or when the file position is reset (duh). ++// ++// History: ++// Keith Wessel - Initial hack, initial idea ++// Andy Reitz - Get it to compile ++// Chris Lattner - Make it work, comment it, no warnings. ++// ++//----------------------------------------------------------------------------- ++ ++#include "chardev.h" ++ ++// The message to spit out. ++const char *message = "Hello world!\nI love kORBit\n"; ++ ++ ++/*** App-specific servant structures ***/ ++ ++typedef struct ++{ ++ POA_CharDev servant; ++ PortableServer_POA poa; ++ int AmountRead; ++ ++} ++impl_POA_CharDev; ++ ++/*** Implementation stub prototypes ***/ ++ ++static inline void impl_CharDev__destroy(impl_POA_CharDev * servant, ++ CORBA_Environment * ev); ++static CORBA_long ++impl_CharDev_read(impl_POA_CharDev * servant, ++ Buffer ** buffer, CORBA_long size, CORBA_Environment * ev); ++ ++/*** epv structures ***/ ++ ++static PortableServer_ServantBase__epv impl_CharDev_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_CharDev__epv impl_CharDev_epv = { ++ NULL, /* _private */ ++ (gpointer) & impl_CharDev_read, ++ ++}; ++ ++/*** vepv structures ***/ ++ ++static POA_CharDev__vepv impl_CharDev_vepv = { ++ &impl_CharDev_base_epv, ++ &impl_CharDev_epv, ++}; ++ ++/*** Stub implementations ***/ ++ ++static CharDev ++impl_CharDev__create(PortableServer_POA poa, CORBA_Environment * ev) ++{ ++ CharDev retval; ++ impl_POA_CharDev *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_CharDev, 1); ++ newservant->servant.vepv = &impl_CharDev_vepv; ++ newservant->poa = poa; ++ newservant->AmountRead = 0; // Initialize chardev stuff... ++ ++ POA_CharDev__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static inline void ++impl_CharDev__destroy(impl_POA_CharDev * servant, CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_CharDev__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static CORBA_long ++impl_CharDev_read(impl_POA_CharDev * servant, ++ Buffer ** buffer, CORBA_long ReqSize, CORBA_Environment * ev) ++{ ++ int AvailSize = strlen(message)-servant->AmountRead; ++ CORBA_long retval = (ReqSize > AvailSize) ? AvailSize : ReqSize; ++ ++ *buffer = Buffer__alloc(); ++ (*buffer)->_buffer = CORBA_octet_allocbuf(retval); ++ (*buffer)->_length = retval; ++ ++ strncpy((*buffer)->_buffer, message + servant->AmountRead, retval); ++ servant->AmountRead += retval; ++ return retval; ++} ++ +diff -urN linux-2.4.1/net/korbit/modules/Config.in linux-2.4.1-korbit/net/korbit/modules/Config.in +--- linux-2.4.1/net/korbit/modules/Config.in Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Config.in Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,11 @@ ++# Console server ++# ++dep_tristate ' CORBA Console Server (EXPERIMENTAL)' CONFIG_CORBA_CONSOLE $CONFIG_KORBIT ++ ++dep_tristate ' CORBA Echo Server (EXPERIMENTAL)' CONFIG_CORBA_ECHO $CONFIG_KORBIT ++ ++dep_tristate ' CORBA FileSystem Access (EXPERIMENTAL)' CONFIG_CORBA_FILESERVER $CONFIG_KORBIT ++ ++dep_tristate ' CORBA User-space FileSystem (EXPERIMENTAL)' CONFIG_CORBA_CORBAFS $CONFIG_KORBIT ++ ++dep_tristate ' CORBA Character Device Interface (EXPERIMENTAL)' CONFIG_CORBA_CHARDEV $CONFIG_KORBIT +diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,4 @@ ++/Makefile/1.2/Thu Feb 1 09:47:00 2001// ++/README/1.1/Thu Feb 1 09:47:00 2001// ++/console.idl/1.1/Thu Feb 1 09:47:00 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/Console/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Entries.Log Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,3 @@ ++A D/PerlClient//// ++A D/client//// ++A D/server//// +diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Console/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Repository Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Console +diff -urN linux-2.4.1/net/korbit/modules/Console/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root +--- linux-2.4.1/net/korbit/modules/Console/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/CVS/Root Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Console/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/Makefile +--- linux-2.4.1/net/korbit/modules/Console/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/Makefile Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,11 @@ ++# ++# Makefile for KORBit/modules/Console ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_CONSOLE) := server ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Entries Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,3 @@ ++/Client/1.1/Thu Feb 1 09:47:01 2001// ++/README/1.1/Thu Feb 1 09:47:01 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Repository Thu Feb 1 11:47:01 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Console/PerlClient +diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root +--- linux-2.4.1/net/korbit/modules/Console/PerlClient/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/CVS/Root Thu Feb 1 11:47:01 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/Client linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client +--- linux-2.4.1/net/korbit/modules/Console/PerlClient/Client Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/Client Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,14 @@ ++#!/usr/bin/perl -w ++ ++use CORBA::ORBit idl => [ qw(../console.idl) ]; ++use Error qw(:try); ++use strict; ++ ++my $orb = CORBA::ORB_init("orbit-local-orb"); ++open IOR, "/proc/corba/console-server" or die "no console server found!"; ++my $ior = <IOR>; ++close IOR; ++chomp($ior); # Kill fredrik's newline... ++ ++my $console = $orb->string_to_object($ior); ++$console->print("Hello Strange World"); +diff -urN linux-2.4.1/net/korbit/modules/Console/PerlClient/README linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README +--- linux-2.4.1/net/korbit/modules/Console/PerlClient/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/PerlClient/README Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,3 @@ ++This is a perl client for the Console server. ++ ++ORB: ORBit +diff -urN linux-2.4.1/net/korbit/modules/Console/README linux-2.4.1-korbit/net/korbit/modules/Console/README +--- linux-2.4.1/net/korbit/modules/Console/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/README Thu Feb 1 11:47:00 2001 +@@ -0,0 +1 @@ ++The "hello world" testcase. This is used to write a string to the linux console. +diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Entries Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,4 @@ ++/Makefile/1.2/Thu Feb 1 09:47:01 2001// ++/README/1.1/Thu Feb 1 09:47:01 2001// ++/console-client.c/1.1/Thu Feb 1 09:47:01 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Repository Thu Feb 1 11:47:01 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Console/client +diff -urN linux-2.4.1/net/korbit/modules/Console/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root +--- linux-2.4.1/net/korbit/modules/Console/client/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/CVS/Root Thu Feb 1 11:47:01 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Console/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile +--- linux-2.4.1/net/korbit/modules/Console/client/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/Makefile Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = console ++ ++CFLAGS = -Wall `orbit-config --cflags client` -I../../.. ++LDFLAGS = `orbit-config --libs client` ++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-client: $(OBJS) ++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-client.c: $(PROJECT).h ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-client ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-stubs.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/Console/client/README linux-2.4.1-korbit/net/korbit/modules/Console/client/README +--- linux-2.4.1/net/korbit/modules/Console/client/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/README Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,3 @@ ++C Client to access console server. ++ ++ORB: ORBit +diff -urN linux-2.4.1/net/korbit/modules/Console/client/console-client.c linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c +--- linux-2.4.1/net/korbit/modules/Console/client/console-client.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/client/console-client.c Thu Feb 1 11:47:01 2001 +@@ -0,0 +1,63 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <orb/orbit.h> ++ ++#include "console.h" ++ ++Console console_client; ++ ++int ++main (int argc, char *argv[]) ++{ ++ CORBA_Environment ev; ++ CORBA_ORB orb; ++ char *Message = "Hey dood, nice hair"; ++ int i; ++ ++ int niters = 10; ++ ++ CORBA_exception_init(&ev); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); ++ ++#if 0 ++ for(i = 0; i < (sizeof(theblah) - 1); i++) ++ theblah[i] = 'a'; ++ theblah[sizeof(theblah) - 1] = '\0'; ++#endif ++ ++ if(argc < 2) ++ { ++ printf("Need a binding ID thing as argv[1]\n"); ++ return 1; ++ } ++ ++ if(argc >= 3) ++ niters = atoi(argv[2]); ++ ++ if (argc >= 4) ++ Message = argv[3]; ++ ++ console_client = CORBA_ORB_string_to_object(orb, argv[1], &ev); ++ if (!console_client) { ++ printf("Cannot bind to %s\n", argv[1]); ++ return 1; ++ } ++ ++ printf("corba = %d, console = %d, foobar = %d\n", ++ CORBA_Object_is_a(console_client, "IDL:CORBA/Object:1.0", &ev), ++ CORBA_Object_is_a(console_client, "IDL:Empty:1.0", &ev), ++ CORBA_Object_is_a(console_client, "IDL:Foo/Bar:1.0", &ev)); ++ ++ for(i = 0; i < niters; i++) { ++ Console_print(console_client, Message, &ev); ++ if(ev._major != CORBA_NO_EXCEPTION) { ++ printf("we got exception %d from doNothing!\n", ev._major); ++ return 1; ++ } ++ } ++ ++ CORBA_Object_release(console_client, &ev); ++ CORBA_Object_release((CORBA_Object)orb, &ev); ++ ++ return 0; ++} +diff -urN linux-2.4.1/net/korbit/modules/Console/console.idl linux-2.4.1-korbit/net/korbit/modules/Console/console.idl +--- linux-2.4.1/net/korbit/modules/Console/console.idl Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/console.idl Thu Feb 1 11:47:00 2001 +@@ -0,0 +1,3 @@ ++interface Console { ++ void print(in string TheString); ++}; +diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Entries Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,5 @@ ++/Makefile/1.7/Thu Feb 1 09:47:02 2001// ++/Makefile.user/1.1/Thu Feb 1 09:47:02 2001// ++/README/1.1/Thu Feb 1 09:47:02 2001// ++/console-server.c/1.7/Thu Feb 1 09:47:02 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Repository Thu Feb 1 11:47:02 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Console/server +diff -urN linux-2.4.1/net/korbit/modules/Console/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root +--- linux-2.4.1/net/korbit/modules/Console/server/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/CVS/Root Thu Feb 1 11:47:02 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile +--- linux-2.4.1/net/korbit/modules/Console/server/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,21 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-cons-server.o ++ ++obj-y := console-server.o console-skels.o console-common.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++console-server.c: console.h console-common.c console-skels.c ++ ++ ++console.h console-skels.c: ../console.idl ++ $(ORBIT_IDL) ../console.idl +diff -urN linux-2.4.1/net/korbit/modules/Console/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user +--- linux-2.4.1/net/korbit/modules/Console/server/Makefile.user Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/Makefile.user Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = console ++ ++CFLAGS = -Wall `orbit-config --cflags server` -I../../.. ++LDFLAGS = `orbit-config --libs server` ++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-server: $(OBJS) ++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-server.c: $(PROJECT).h ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-server ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-skels.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/Console/server/README linux-2.4.1-korbit/net/korbit/modules/Console/server/README +--- linux-2.4.1/net/korbit/modules/Console/server/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/README Thu Feb 1 11:47:02 2001 +@@ -0,0 +1 @@ ++Kernel module to implement Console server. +diff -urN linux-2.4.1/net/korbit/modules/Console/server/console-server.c linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c +--- linux-2.4.1/net/korbit/modules/Console/server/console-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Console/server/console-server.c Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,85 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <signal.h> ++#include <orb/orbit.h> ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include "console.h" ++#include "glib.h" ++#include "korbit.h" ++ ++Console console_client = CORBA_OBJECT_NIL; ++ ++static void corba_console_print(PortableServer_Servant _servant, ++ CORBA_char *TheString, ++ CORBA_Environment *ev); ++ ++PortableServer_ServantBase__epv base_epv = { ++ NULL, ++ NULL, ++ NULL ++}; ++POA_Console__epv console_epv = { NULL, corba_console_print }; ++POA_Console__vepv poa_console_vepv = { &base_epv, &console_epv }; ++POA_Console poa_console_servant = { NULL, &poa_console_vepv }; ++ ++// MAke this global so that I can unregister the module... ++PortableServer_ObjectId objid = {0, sizeof("myFoo"), "myFoo"}; ++CORBA_Environment *ev; ++PortableServer_POA poa; ++ ++#ifdef __KERNEL__ ++int __init corba_console_init(void) ++#else ++int main(int argc, char *argv[]) ++#endif ++{ ++#ifdef __KERNEL__ ++ int argc = 1; char *argv[] = { "server", 0 }; ++#endif ++ CORBA_ORB orb; ++ ++ ev = g_new0(CORBA_Environment, 1); ++ CORBA_exception_init(ev); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ ++ poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev); ++ PortableServer_POAManager_activate(PortableServer_POA__get_the_POAManager(poa, ev), ev); ++ ++ POA_Console__init(&poa_console_servant, ev); ++ ++ PortableServer_POA_activate_object_with_id(poa, ++ &objid, &poa_console_servant, ev); ++ ++ console_client = ++ PortableServer_POA_servant_to_reference(poa, &poa_console_servant, ev); ++ if (!console_client) { ++ printf("Cannot get objref\n"); ++ return 1; ++ } ++ ++ korbit_register_ior("console-server", console_client, orb, ev); ++ ++ CORBA_ORB_run(orb, ev); ++ ++ return 0; ++} ++ ++#ifdef __KERNEL__ ++void corba_console_exit(void) { ++ PortableServer_POA_deactivate_object(poa, &objid, ev); ++ remove_proc_entry("corba/console-server", 0); ++} ++ ++module_init(corba_console_init) ++module_exit(corba_console_exit) ++#endif ++ ++static void corba_console_print(PortableServer_Servant _servant, ++ CORBA_char *TheString, ++ CORBA_Environment *ev) { ++ printf("Yo. Dood. You said: '%s'!\n", TheString); ++} ++ +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,4 @@ ++/CorbaFS.idl/1.7/Thu Feb 1 09:47:02 2001// ++/Makefile/1.4/Thu Feb 1 09:47:02 2001// ++/README/1.2/Thu Feb 1 09:47:02 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Entries.Log Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,3 @@ ++A D/client//// ++A D/server//// ++A D/server-perl//// +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Repository Thu Feb 1 11:47:02 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root +--- linux-2.4.1/net/korbit/modules/CorbaFS/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CVS/Root Thu Feb 1 11:47:02 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl +--- linux-2.4.1/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/CorbaFS.idl Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,38 @@ ++// ----------------------------------------------------------------------------- ++// CorbaDS Module - Implement Kernel functionality in Korba ++// ----------------------------------------------------------------------------- ++// ++// Main source of information: ++// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html ++// ++module CorbaFS { ++ ++ struct dirent ++ { ++ long inode; // inode number ++ string name; // file name (null-terminated) ++ }; ++ ++ typedef sequence<dirent> DirEntSeq; ++ typedef sequence<octet> Buffer; ++ ++ interface Inode { ++ void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid, ++ out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks, ++ out long atime, out long mtime, out long ctime); ++ void readpage(out Buffer buffer, in long size, in long offset); ++ void release(); ++ }; ++ ++ interface FileSystem { ++ Inode getInode(in string path); ++ ++ // DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT ++ // field of the mode value. ++ DirEntSeq readdir(in string path); ++ ++ // SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT ++ // field of the mode value. ++ string readlink(in string filename); ++ }; ++}; +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile +--- linux-2.4.1/net/korbit/modules/CorbaFS/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/Makefile Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,11 @@ ++# ++# Makefile for KORBit - CorbaFS ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_CORBAFS) := client ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README +--- linux-2.4.1/net/korbit/modules/CorbaFS/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/README Thu Feb 1 11:47:02 2001 +@@ -0,0 +1,14 @@ ++This interface is used to implement linux FileSystems in CORBA. ++ ++Status: Working for readonly filesystems. Write capability is a todo. ++ ++This lets you do all kinds of interesting things (just like the user level ++filesystem proposals would let you do): ++ server/ implements NFS like capability of just exporting an existing FS ++ TODO: webfs, ftpfs, cvsfs, mysqlfs... ++ ++Usage: ++ insmod corba-corbafs.o ++ mount -t corbafs -o IOR:... none /mnt/corbafs ++ ++Where the IOR comes from a filesystem server that you run somewhere... +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Entries Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,6 @@ ++/CorbaFS-client.c/1.9/Thu Feb 1 09:47:03 2001// ++/CorbaFS-user-client.c/1.3/Thu Feb 1 09:47:03 2001// ++/Makefile/1.4/Thu Feb 1 09:47:03 2001// ++/Makefile.user/1.1/Thu Feb 1 09:47:03 2001// ++/README/1.1/Thu Feb 1 09:47:03 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Repository Thu Feb 1 11:47:03 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/client +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CVS/Root Thu Feb 1 11:47:03 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-client.c Fri Feb 2 02:20:21 2001 +@@ -0,0 +1,469 @@ ++/* ++ * corbafs - Interface glue between native linux VFS layer and CORBA ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/pagemap.h> ++#include <linux/init.h> ++#include <linux/string.h> ++#include <linux/locks.h> ++#include <linux/dirent.h> ++#include <linux/module.h> ++ ++#include <asm/uaccess.h> ++#include "CorbaFS.h" ++ ++/* some random number */ ++#define CORBAFS_MAGIC 0xC02BAF5 ++ ++// CORBA Stuff... ++CORBA_ORB orb; ++CORBA_Environment *ev; ++ ++ ++/* ++ * FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS FILE OPERATIONS ++ */ ++ ++/* Declarations for the file_operations structure for normal files... ++ */ ++static struct file_operations corbafs_file_operations = { ++ read: generic_file_read, ++}; ++ ++ ++/* Declarations for the file_operations structure for directories... ++ */ ++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir); ++ ++static struct file_operations corbafs_dir_operations = { ++ read: generic_read_dir, ++ readdir: corbafs_readdir, ++}; ++ ++ ++/* ++ * INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS INODE OPERATIONS ++ */ ++ ++/* Declarations for the inode_operations structure for symlinks... ++ */ ++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen); ++static int corbafs_followlink(struct dentry *link, struct nameidata *nd); ++ ++static struct inode_operations corbafs_symlink_inode_operations = { ++ readlink: corbafs_readlink, ++ follow_link: corbafs_followlink, ++}; ++ ++ ++/* Declarations for the inode_operations structure for directories... ++ */ ++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry); ++ ++static struct inode_operations corbafs_dir_inode_operations = { ++ lookup: corbafs_lookup, ++}; ++ ++ ++/* ++ * OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS OTHER OPERATIONS ++ */ ++ ++/* Declarations for the corba FS's address space ops... ++ */ ++static int corbafs_readpage(struct file *file, struct page * page); ++ ++static struct address_space_operations corbafs_aops = { ++ readpage: corbafs_readpage, ++}; ++ ++ ++/* Declarations for the super_operations structure... ++ */ ++static int corbafs_statfs(struct super_block *sb, struct statfs *buf); ++static void corbafs_delete_inode(struct inode *); ++ ++static struct super_operations corbafs_ops = { ++ statfs: corbafs_statfs, ++ delete_inode: corbafs_delete_inode, ++}; ++ ++ ++ ++ ++/* do_local_path - Modified version of d_path that is used to get the remote ++ * filename that a dentry represents... ++ */ ++static char *d_local_path(struct dentry *dentry, char *buffer, int buflen) { ++ char * end = buffer+buflen; ++ char * retval; ++ int namelen; ++ ++ *--end = '\0'; ++ buflen--; ++ ++ /* Get '/' right */ ++ retval = end-1; ++ *retval = '/'; ++ for (;;) { ++ if (IS_ROOT(dentry)) { ++ if (dentry->d_name.len > 1 || ++ dentry->d_name.name[0] != '/' || ++ retval != end) { /* Only for root directory */ ++ namelen = dentry->d_name.len; ++ buflen -= namelen; ++ if (buflen >= 0) { ++ end -= namelen; ++ memcpy(end, dentry->d_name.name, namelen); ++ } ++ } ++ return end; ++ } ++ namelen = dentry->d_name.len; ++ buflen -= namelen + 1; ++ if (buflen < 0) ++ break; ++ end -= namelen; ++ memcpy(end, dentry->d_name.name, namelen); ++ *--end = '/'; ++ retval = end; ++ if (dentry == dentry->d_parent) break; ++ dentry = dentry->d_parent; ++ } ++ return retval; ++} ++ ++ ++/* corbafs_readpage - This request should be between a file_open and a ++ * file_release, so file_fd(f) should be valid. Just read the buffer... ++ */ ++static int corbafs_readpage(struct file *f, struct page * page) ++{ ++ struct inode *d_inode = f->f_dentry->d_inode; ++ CorbaFS_Inode inode; ++ CorbaFS_Buffer *buffer = NULL; ++ ++ int offset = page->index*PAGE_CACHE_SIZE; ++ int bytesRead; ++ ++#if 0 ++ printk("*** READPAGE 0x%p: 0x%lX->0x%lX to 0x%p\n", ++ f, ++ page->index, ++ page->index*PAGE_CACHE_SIZE, ++ page_address(page)); ++#endif ++ ++ inode = d_inode->u.generic_ip; ++ if (!inode) return -EPERM; ++ ++ CorbaFS_Inode_readpage(inode, &buffer, PAGE_CACHE_SIZE, offset, ev); ++ if (!buffer) return -EPERM; /* ??? */ ++ ++ bytesRead = buffer->_length; ++ memcpy(page_address(page), buffer->_buffer, bytesRead); ++ ++ if (bytesRead != PAGE_CACHE_SIZE) { /* EOF? */ ++ /* Zero out rest of page for security. */ ++ memset((void*)(page_address(page)+bytesRead), 0, ++ PAGE_CACHE_SIZE-bytesRead); ++ } ++ ++ SetPageUptodate(page); ++ UnlockPage(page); ++ return 0; ++} ++ ++ ++ ++struct inode *corbafs_get_inode(struct super_block *sb, const char *path) ++{ ++ struct inode * inode = get_empty_inode(); ++ CorbaFS_FileSystem fs_client; ++ CorbaFS_Inode newInode; ++ ++ if (!inode) return 0; ++ ++ inode->i_sb = sb; ++ inode->i_dev = sb->s_dev; ++ ++ fs_client = sb->u.generic_sbp; ++//printk("\n \n \nCorbaFS_FileSystem_getInode(0x%X, %s)\n", fs_client, path); ++ newInode = CorbaFS_FileSystem_getInode(fs_client, path, ev); ++//printk("NewInode = 0x%X\n \n \n \n", newInode); ++ if (!newInode) { ++ iput(inode); ++ return NULL; ++ } ++ ++//printk("CorbaFS_Inode_getStatus\n"); ++ CorbaFS_Inode_getStatus(newInode, ++ &inode->i_mode, &inode->i_uid, &inode->i_gid, ++ (CORBA_unsigned_long *)&inode->i_size, ++ (CORBA_unsigned_long *)&inode->i_ino, ++ &inode->i_nlink, ++ (CORBA_long *)&inode->i_atime, ++ (CORBA_long *)&inode->i_mtime, ++ (CORBA_long *)&inode->i_ctime, ++ ev); ++//printk("Back from CorbaFS_Inode_getStatus\n \n \n \n"); ++ ++ inode->u.generic_ip = (void*)newInode; ++ ++ /* TODO: Map things back correctly??? */ ++ inode->i_uid = 0 /*current->fsuid */; ++ inode->i_gid = 0 /*current->fsgid */; ++ ++ inode->i_blksize = PAGE_CACHE_SIZE; ++ inode->i_blocks = 0; ++ inode->i_rdev = 0; ++ inode->i_op = NULL; ++ inode->i_fop = NULL; ++ inode->i_mapping->a_ops = &corbafs_aops; ++ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ ++ switch (inode->i_mode & S_IFMT) { ++ default: ++ /* Do I really want to expose device inodes? */ ++ init_special_inode(inode, inode->i_mode, sb->s_dev); ++ break; ++ case S_IFREG: ++ inode->i_fop = &corbafs_file_operations; ++ break; ++ case S_IFDIR: ++ inode->i_op = &corbafs_dir_inode_operations; ++ inode->i_fop = &corbafs_dir_operations; ++ break; ++ case S_IFLNK: ++ inode->i_op = &corbafs_symlink_inode_operations; ++ break; ++ } ++ insert_inode_hash(inode); ++ ++ return inode; ++} ++ ++static int corbafs_readdir(struct file *file, void *data, filldir_t filldir) ++{ ++ struct inode *inode = file->f_dentry->d_inode; ++ struct super_block *sb = file->f_dentry->d_sb; ++ unsigned offset = file->f_pos; ++ char *path, *page = (char *)__get_free_page(GFP_KERNEL); ++ int i; ++ unsigned char d_type = DT_UNKNOWN; ++ CorbaFS_FileSystem fs_client; ++ CorbaFS_DirEntSeq *dirEntSeq; ++ CorbaFS_dirent *dirEnts; ++ ++ if (offset >= inode->i_size) return 0; ++ ++ path = d_local_path(file->f_dentry, page, PAGE_SIZE); ++ ++ fs_client = sb->u.generic_sbp; ++ if (!fs_client) ++ return -EPERM; /* ??? */ ++ ++// printk("\n \n \nCorbaFS_FileSystem_readdir(%s)\n", path); ++ ++ dirEntSeq = CorbaFS_FileSystem_readdir(fs_client, path, ev); ++ ++// printk("CorbaFS_FileSystem_readdir = %d\n \n \n \n", dirEntSeq->_length); ++ ++ if (dirEntSeq->_length == 0) goto full; ++ ++ dirEnts = dirEntSeq->_buffer; ++ i = 0; ++ if (offset) { // We have read PART of the directory ++ int idxadj = offset; // Start reading now from where we left ++ while (idxadj > 0) { // off... ++ idxadj -= sizeof(struct dirent)+ ++ strlen(dirEnts[i].name); ++ i++; ++ } ++ ++ if (idxadj < 0) { // We should end up with exactly 0. ++ printf("Alert! Readdir can't resume in the middle " ++ "of a directory! stopage.\n"); ++ goto full; ++ } ++ } ++ ++ for (; i < dirEntSeq->_length; i++) { ++ int myinode = dirEnts[i].inode; ++ char *myname = dirEnts[i].name; ++ int namelen = strlen(myname); ++ ++ if (filldir(data, myname, namelen, offset, myinode, d_type)) ++ goto full; ++ offset += sizeof(struct dirent)+namelen; ++ } ++ ++ full: ++ file->f_pos = offset; ++ return 0; ++} ++ ++static int corbafs_statfs(struct super_block *sb, struct statfs *buf) { ++ buf->f_type = CORBAFS_MAGIC; ++ buf->f_bsize = PAGE_CACHE_SIZE; ++ buf->f_namelen = 255; ++ return 0; ++} ++ ++/* ++ * Lookup the data. Most of the grunt work is done by corbafs_get_inode. ++ */ ++static struct dentry *corbafs_lookup(struct inode *dir, struct dentry *dentry) ++{ ++ struct inode *New; ++ char *Path, *Page = (char *)__get_free_page(GFP_KERNEL); ++ if (Page == 0) goto out; /* nomem? */ ++ ++ Path = d_local_path(dentry, Page, PAGE_SIZE); ++ ++ New = corbafs_get_inode(dir->i_sb, Path); ++ free_page((unsigned long)Page); ++ ++ if (New) { ++ d_add(dentry, New); ++ return 0; ++ } ++ ++out: ++ d_add(dentry, NULL); ++ return 0; ++} ++ ++ ++static char *corbafs_read_a_link(struct dentry *dentry) { ++ char *path, *page, *s = 0; ++ struct super_block *sb = dentry->d_sb; ++ CorbaFS_FileSystem fs_client; ++ ++ page = (char *)__get_free_page(GFP_KERNEL); ++ if (page == 0) goto out; /* nomem? */ ++ ++ path = d_local_path(dentry, page, PAGE_SIZE); ++ ++ fs_client = sb->u.generic_sbp; ++// printk("\n \n \nCorbaFS_FileSystem_readlink(%s)\n", path); ++ s = CorbaFS_FileSystem_readlink(fs_client, path, ev); ++// printk("CorbaFS_FileSystem_readlink = %s\n \n \n \n", s); ++ ++ if (ev->_major != CORBA_NO_EXCEPTION) { ++ if (s) { ++ // CORBA_string_free(s,..); ++ s = 0; ++ } ++ goto outfree; ++ } ++ outfree: ++ free_page((unsigned long)page); ++ out: ++ return s; ++} ++ ++ ++static int corbafs_readlink(struct dentry *dentry, char *buffer, int buflen) { ++ char *str = corbafs_read_a_link(dentry); ++ int error = -EINVAL; ++ ++ if (str) { ++ error = vfs_readlink(dentry, buffer, buflen, str); ++ // TODO: CORBA_string__free the string str. ++ } ++ return error; ++} ++ ++/* Fill in nd->dentry ++ */ ++static int corbafs_followlink(struct dentry *link, struct nameidata *nd) { ++ int Error = -ENOMEM; ++ char *Path = corbafs_read_a_link(link); ++ if (!Path) goto out; ++ ++#if 1 ++ printk("Followlink: %s\n", Path); ++#endif ++ Error = vfs_follow_link(nd, Path); ++ // TODO: CORBA_string__free the string str. ++ ++ out: ++ return Error; ++} ++ ++static void corbafs_delete_inode(struct inode *inode) { ++ CorbaFS_Inode Inode = inode->u.generic_ip; ++// printk("\n \n \nCorbaFS_Inode_Release\n"); ++ CorbaFS_Inode_release(Inode, ev); ++// printk("CorbaFS_Inode_Release done\n \n \n \n"); ++} ++ ++static void corbafs_put_super(struct super_block *sb) { ++// MOD_DEC_USE_COUNT; ++} ++ ++static struct super_block *corbafs_read_super(struct super_block * sb, void * data, int silent) { ++ struct dentry *root = 0; ++ struct inode *root_inode = 0; ++ ++ CorbaFS_FileSystem fs_client; ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ sb->s_magic = CORBAFS_MAGIC; ++ sb->s_op = &corbafs_ops; ++ ++//printk("corbafs_read_super: '%s'\n", (char*)data); ++ ++ // Note that the CORBA IOR is now in *data ++ fs_client = CORBA_ORB_string_to_object(orb, data, ev); ++ ++//printk("fs_client: 0x%X\n", fs_client); ++ if (!fs_client) ++ return NULL; ++ ++ sb->u.generic_sbp = fs_client; ++ ++ root_inode = corbafs_get_inode(sb, "/"); ++//printk("root_inode = 0x%X\n", root_inode); ++ root = d_alloc_root(root_inode); ++ if (!root) { ++ iput(root_inode); ++ return NULL; ++ } ++ sb->s_root = root; ++ ++// MOD_INC_USE_COUNT; ++ return sb; ++} ++ ++static DECLARE_FSTYPE(corbafs_fs_type, "corbafs", corbafs_read_super, 0); ++ ++static int __init init_corbafs_fs(void) { ++ int argc = 1; ++ char *argv[] = { "client", 0 }; ++ ev = g_new0(CORBA_Environment,1); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ ++ return register_filesystem(&corbafs_fs_type); ++} ++ ++static void __exit exit_corbafs_fs(void) ++{ ++ // remove object from orb. ++ printf("\n \n \nCorbaFS_exit()\n"); ++ unregister_filesystem(&corbafs_fs_type); ++ CORBA_Object_release((CORBA_Object)orb, ev); ++} ++ ++module_init(init_corbafs_fs) ++module_exit(exit_corbafs_fs) ++ ++/* ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-common.c Thu Feb 1 16:36:08 2001 +@@ -0,0 +1,370 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "CorbaFS.h" ++ ++#if ( (TC_IMPL_TC_CorbaFS_dirent_0 == 'C') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_1 == 'o') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_2 == 'r') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_3 == 'b') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_4 == 'a') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_5 == 'F') \ ++&& (TC_IMPL_TC_CorbaFS_dirent_6 == 'S') \ ++) && !defined(TC_DEF_TC_CorbaFS_dirent) ++#define TC_DEF_TC_CorbaFS_dirent 1 ++static const char *anon_subnames_array1[] = { "inode", "name" }; ++static const CORBA_TypeCode anon_subtypes_array2[] = ++ { (CORBA_TypeCode) & TC_CORBA_long_struct, ++ (CORBA_TypeCode) & TC_CORBA_string_struct }; ++const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_struct, "dirent", "IDL:CorbaFS/dirent:1.0", ++ 0, 2, ++ (const char **) anon_subnames_array1, ++ (CORBA_TypeCode *) anon_subtypes_array2, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \ ++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent) ++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1 ++static const CORBA_TypeCode anon_subtypes_array6[] = ++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct }; ++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_sequence, NULL, NULL, ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array6, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 == 'C') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 == 'o') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 == 'r') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 == 'b') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 == 'a') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 == 'F') \ ++&& (TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 == 'S') \ ++) && !defined(TC_DEF_TC_CORBA_sequence_CorbaFS_dirent) ++#define TC_DEF_TC_CORBA_sequence_CorbaFS_dirent 1 ++static const CORBA_TypeCode anon_subtypes_array15[] = ++ { (CORBA_TypeCode) & TC_CorbaFS_dirent_struct }; ++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CorbaFS_dirent_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_sequence, NULL, NULL, ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array15, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CorbaFS_DirEntSeq_0 == 'C') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_1 == 'o') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_2 == 'r') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_3 == 'b') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_4 == 'a') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_5 == 'F') \ ++&& (TC_IMPL_TC_CorbaFS_DirEntSeq_6 == 'S') \ ++) && !defined(TC_DEF_TC_CorbaFS_DirEntSeq) ++#define TC_DEF_TC_CorbaFS_DirEntSeq 1 ++static const CORBA_TypeCode anon_subtypes_array19[] = ++ { (CORBA_TypeCode) & TC_CORBA_sequence_CorbaFS_dirent_struct }; ++const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_alias, "DirEntSeq", "IDL:CorbaFS/DirEntSeq:1.0", ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array19, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \ ++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet) ++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1 ++static const CORBA_TypeCode anon_subtypes_array23[] = ++ { (CORBA_TypeCode) & TC_CORBA_octet_struct }; ++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_sequence, NULL, NULL, ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array23, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 == 'C') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 == 'o') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 == 'r') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 == 'b') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 == 'a') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 == 'F') \ ++&& (TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 == 'S') \ ++) && !defined(TC_DEF_TC_CORBA_sequence_CORBA_octet) ++#define TC_DEF_TC_CORBA_sequence_CORBA_octet 1 ++static const CORBA_TypeCode anon_subtypes_array32[] = ++ { (CORBA_TypeCode) & TC_CORBA_octet_struct }; ++const struct CORBA_TypeCode_struct TC_CORBA_sequence_CORBA_octet_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_sequence, NULL, NULL, ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array32, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CorbaFS_Buffer_0 == 'C') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_1 == 'o') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_2 == 'r') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_3 == 'b') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_4 == 'a') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_5 == 'F') \ ++&& (TC_IMPL_TC_CorbaFS_Buffer_6 == 'S') \ ++) && !defined(TC_DEF_TC_CorbaFS_Buffer) ++#define TC_DEF_TC_CorbaFS_Buffer 1 ++static const CORBA_TypeCode anon_subtypes_array36[] = ++ { (CORBA_TypeCode) & TC_CORBA_sequence_CORBA_octet_struct }; ++const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_alias, "Buffer", "IDL:CorbaFS/Buffer:1.0", ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array36, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CorbaFS_Inode_0 == 'C') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_1 == 'o') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_2 == 'r') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_3 == 'b') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_4 == 'a') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_5 == 'F') \ ++&& (TC_IMPL_TC_CorbaFS_Inode_6 == 'S') \ ++) && !defined(TC_DEF_TC_CorbaFS_Inode) ++#define TC_DEF_TC_CorbaFS_Inode 1 ++const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_objref, "Inode", "IDL:CorbaFS/Inode:1.0", ++ 0, 0, ++ NULL, ++ NULL, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++#if ( (TC_IMPL_TC_CorbaFS_FileSystem_0 == 'C') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_1 == 'o') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_2 == 'r') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_3 == 'b') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_4 == 'a') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_5 == 'F') \ ++&& (TC_IMPL_TC_CorbaFS_FileSystem_6 == 'S') \ ++) && !defined(TC_DEF_TC_CorbaFS_FileSystem) ++#define TC_DEF_TC_CorbaFS_FileSystem 1 ++const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_objref, "FileSystem", "IDL:CorbaFS/FileSystem:1.0", ++ 0, 0, ++ NULL, ++ NULL, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++gpointer ++CorbaFS_dirent__free(gpointer mem, gpointer dat, CORBA_boolean free_strings) ++{ ++ CorbaFS_dirent *var = mem; ++ ++ if (free_strings) { ++ CORBA_string__free(&(var->name), NULL, free_strings); ++ } ++ return (gpointer) (var + 1); ++} ++ ++CorbaFS_dirent * ++CorbaFS_dirent__alloc(void) ++{ ++ CorbaFS_dirent *retval; ++ ++ retval = ++ ORBit_alloc(sizeof(CorbaFS_dirent), ++ (ORBit_free_childvals) CorbaFS_dirent__free, ++ GUINT_TO_POINTER(1)); ++ memset(&(retval->name), '\0', sizeof(retval->name)); ++ return retval; ++} ++ ++#if ( (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 == 'C') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 == 'o') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 == 'r') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 == 'b') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 == 'a') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 == 'F') \ ++&& (ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 == 'S') \ ++) && !defined(ORBIT_DEF_CORBA_sequence_CorbaFS_dirent) ++#define ORBIT_DEF_CORBA_sequence_CorbaFS_dirent 1 ++ ++gpointer ++CORBA_sequence_CorbaFS_dirent__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings) ++{ ++ CORBA_sequence_CorbaFS_dirent *val = mem; ++ ++ if (val->_release) ++ ORBit_free(val->_buffer, free_strings); ++ return (gpointer) (val + 1); ++} ++ ++CORBA_sequence_CorbaFS_dirent * ++CORBA_sequence_CorbaFS_dirent__alloc(void) ++{ ++ CORBA_sequence_CorbaFS_dirent *retval; ++ ++ retval = ++ ORBit_alloc(sizeof(CORBA_sequence_CorbaFS_dirent), ++ (ORBit_free_childvals) CORBA_sequence_CorbaFS_dirent__free, ++ GUINT_TO_POINTER(1)); ++ retval->_maximum = 0; ++ retval->_length = 0; ++ retval->_buffer = NULL; ++ retval->_release = CORBA_FALSE; ++ return retval; ++} ++ ++CorbaFS_dirent * ++CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long len) ++{ ++ CorbaFS_dirent *retval = ++ ORBit_alloc(sizeof(CorbaFS_dirent) * len, ++ (ORBit_free_childvals) CorbaFS_dirent__free, ++ GUINT_TO_POINTER(len)); ++ ++ memset(retval, '\0', sizeof(CorbaFS_dirent) * len); ++ return retval; ++} ++#endif ++ ++gpointer ++CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings) ++{ ++ return CORBA_sequence_CorbaFS_dirent__free(mem, dat, free_strings); ++} ++ ++CorbaFS_DirEntSeq * ++CorbaFS_DirEntSeq__alloc(void) ++{ ++ return CORBA_sequence_CorbaFS_dirent__alloc(); ++} ++ ++#if ( (ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 == 'C') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 == 'o') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 == 'r') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 == 'b') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 == 'a') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 == 'F') \ ++&& (ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 == 'S') \ ++) && !defined(ORBIT_DEF_CORBA_sequence_CORBA_octet) ++#define ORBIT_DEF_CORBA_sequence_CORBA_octet 1 ++ ++gpointer ++CORBA_sequence_CORBA_octet__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings) ++{ ++ CORBA_sequence_CORBA_octet *val = mem; ++ ++ if (val->_release) ++ ORBit_free(val->_buffer, free_strings); ++ return (gpointer) (val + 1); ++} ++ ++CORBA_sequence_CORBA_octet * ++CORBA_sequence_CORBA_octet__alloc(void) ++{ ++ CORBA_sequence_CORBA_octet *retval; ++ ++ retval = ++ ORBit_alloc(sizeof(CORBA_sequence_CORBA_octet), ++ (ORBit_free_childvals) CORBA_sequence_CORBA_octet__free, ++ GUINT_TO_POINTER(1)); ++ retval->_maximum = 0; ++ retval->_length = 0; ++ retval->_buffer = NULL; ++ retval->_release = CORBA_FALSE; ++ return retval; ++} ++ ++CORBA_octet * ++CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len) ++{ ++ CORBA_octet *retval = ++ ORBit_alloc(sizeof(CORBA_octet) * len, (ORBit_free_childvals) NULL, ++ GUINT_TO_POINTER(len)); ++ ++ return retval; ++} ++#endif ++ ++gpointer ++CorbaFS_Buffer__free(gpointer mem, gpointer dat, CORBA_boolean free_strings) ++{ ++ return CORBA_sequence_CORBA_octet__free(mem, dat, free_strings); ++} ++ ++CorbaFS_Buffer * ++CorbaFS_Buffer__alloc(void) ++{ ++ return CORBA_sequence_CORBA_octet__alloc(); ++} ++ ++CORBA_unsigned_long CorbaFS_Inode__classid = 0; ++CORBA_unsigned_long CorbaFS_FileSystem__classid = 0; +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-stubs.c Thu Feb 1 16:36:08 2001 +@@ -0,0 +1,791 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "CorbaFS.h" ++ ++void ++CorbaFS_Inode_getStatus(CorbaFS_Inode _obj, CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, CORBA_long * atime, ++ CORBA_long * mtime, CORBA_long * ctime, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) { ++ ++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])-> ++ getStatus(_obj->servant, mode, uid, gid, size, inodeNum, numLinks, ++ atime, mtime, ctime, ev); ++ return; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[10]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 10, "getStatus"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 14 }; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2); ++ ++ (*((guint16 *) & ((*mode)))) = ++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 2; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & ((*uid)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint32 *) & ((*gid)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint32 *) & ((*size)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint32 *) & ((*inodeNum)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint16 *) & ((*numLinks)))) = ++ GUINT16_SWAP_LE_BE(*((guint16 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 2; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & ((*atime)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint32 *) & ((*mtime)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ (*((guint32 *) & ((*ctime)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 2); ++ (*mode) = *((CORBA_unsigned_short *) _ORBIT_curptr); ++ _ORBIT_curptr += 2; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*uid) = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*gid) = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*size) = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*inodeNum) = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*numLinks) = *((CORBA_unsigned_short *) _ORBIT_curptr); ++ _ORBIT_curptr += 2; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*atime) = *((CORBA_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*mtime) = *((CORBA_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ (*ctime) = *((CORBA_long *) _ORBIT_curptr); ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ } ++ } ++} ++void ++CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer, ++ const CORBA_long size, const CORBA_long offset, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ register CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) { ++ ++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])-> ++ readpage(_obj->servant, buffer, size, offset, ev); ++ return; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[9]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 9, "readpage"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 13 }; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ &(size), sizeof(size)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ &(offset), sizeof(offset)); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ *buffer = CorbaFS_Buffer__alloc(); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & (((**buffer))._length))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ ++ ((**buffer))._buffer = ++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length); ++ ((**buffer))._release = CORBA_TRUE; ++ memcpy(((**buffer))._buffer, _ORBIT_curptr, ++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) * ++ ((**buffer))._length); ++ _ORBIT_curptr += ++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) * ++ ((**buffer))._length; ++ } else { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ((**buffer))._length = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ ++ ((**buffer))._buffer = ++ CORBA_sequence_CORBA_octet_allocbuf(((**buffer))._length); ++ ((**buffer))._release = CORBA_TRUE; ++ memcpy(((**buffer))._buffer, _ORBIT_curptr, ++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) * ++ ((**buffer))._length); ++ _ORBIT_curptr += ++ sizeof(((**buffer))._buffer[_ORBIT_tmpvar_1]) * ++ ((**buffer))._length; ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ } ++ } ++} ++void ++CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_Inode__classid) { ++ ++ ((POA_CorbaFS_Inode__epv *) _obj->vepv[CorbaFS_Inode__classid])-> ++ release(_obj->servant, ev); ++ return; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[8]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 8, "release"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 12 }; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ } else { ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return; ++ } ++ } ++} ++CorbaFS_Inode ++CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj, const CORBA_char * path, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ CorbaFS_Inode _ORBIT_retval; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) { ++ _ORBIT_retval = ++ ((POA_CorbaFS_FileSystem__epv *) _obj-> ++ vepv[CorbaFS_FileSystem__classid])->getInode(_obj->servant, path, ++ ev); ++ return _ORBIT_retval; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[9]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 9, "getInode"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 13 }; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(path) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ { ++ guchar *_ORBIT_t; ++ ++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1)); ++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), (_ORBIT_t), ++ sizeof(_ORBIT_tmpvar_1)); ++ } ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ (path), ++ sizeof(path[_ORBIT_tmpvar_0]) * ++ _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ } else { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++} ++CorbaFS_DirEntSeq * ++CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj, const CORBA_char * path, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ CorbaFS_DirEntSeq *_ORBIT_retval; ++ register CORBA_unsigned_long _ORBIT_tmpvar_5; ++ register CORBA_unsigned_long _ORBIT_tmpvar_6; ++ CORBA_unsigned_long _ORBIT_tmpvar_7; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) { ++ _ORBIT_retval = ++ ((POA_CorbaFS_FileSystem__epv *) _obj-> ++ vepv[CorbaFS_FileSystem__classid])->readdir(_obj->servant, path, ++ ev); ++ return _ORBIT_retval; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[8]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 8, "readdir"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 12 }; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(path) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ { ++ guchar *_ORBIT_t; ++ ++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1)); ++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), (_ORBIT_t), ++ sizeof(_ORBIT_tmpvar_1)); ++ } ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ (path), ++ sizeof(path[_ORBIT_tmpvar_0]) * ++ _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_retval = CorbaFS_DirEntSeq__alloc(); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & ((*_ORBIT_retval)._length))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ ++ (*_ORBIT_retval)._buffer = ++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length); ++ (*_ORBIT_retval)._release = CORBA_TRUE; ++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length; ++ _ORBIT_tmpvar_5++) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (* ++ ((guint32 *) & ++ ((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode))) = ++GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ ++ (*((guint32 *) & (_ORBIT_tmpvar_7))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ ++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name = ++ CORBA_string_alloc(_ORBIT_tmpvar_7); ++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name, ++ _ORBIT_curptr, ++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5]. ++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7); ++ _ORBIT_curptr += ++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5]. ++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7; ++ } ++ ++ } else { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*_ORBIT_retval)._length = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ ++ (*_ORBIT_retval)._buffer = ++ CORBA_sequence_CorbaFS_dirent_allocbuf((*_ORBIT_retval)._length); ++ (*_ORBIT_retval)._release = CORBA_TRUE; ++ for (_ORBIT_tmpvar_5 = 0; _ORBIT_tmpvar_5 < (*_ORBIT_retval)._length; ++ _ORBIT_tmpvar_5++) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].inode = *((CORBA_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ _ORBIT_tmpvar_7 = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ ++ (*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name = ++ CORBA_string_alloc(_ORBIT_tmpvar_7); ++ memcpy((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5].name, ++ _ORBIT_curptr, ++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5]. ++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7); ++ _ORBIT_curptr += ++ sizeof((*_ORBIT_retval)._buffer[_ORBIT_tmpvar_5]. ++ name[_ORBIT_tmpvar_6]) * _ORBIT_tmpvar_7; ++ } ++ ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++} ++CORBA_char * ++CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj, ++ const CORBA_char * filename, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ CORBA_char *_ORBIT_retval; ++ register CORBA_unsigned_long _ORBIT_tmpvar_4; ++ CORBA_unsigned_long _ORBIT_tmpvar_5; ++ ++ if (_obj->servant && _obj->vepv && CorbaFS_FileSystem__classid) { ++ _ORBIT_retval = ++ ((POA_CorbaFS_FileSystem__epv *) _obj-> ++ vepv[CorbaFS_FileSystem__classid])->readlink(_obj->servant, ++ filename, ev); ++ return _ORBIT_retval; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[9]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 9, "readlink"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 13 }; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(filename) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ { ++ guchar *_ORBIT_t; ++ ++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1)); ++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), (_ORBIT_t), ++ sizeof(_ORBIT_tmpvar_1)); ++ } ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ (filename), ++ sizeof(filename[_ORBIT_tmpvar_0]) * ++ _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & (_ORBIT_tmpvar_5))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5); ++ memcpy(_ORBIT_retval, _ORBIT_curptr, ++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5); ++ _ORBIT_curptr += ++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5; ++ } else { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ _ORBIT_tmpvar_5 = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ _ORBIT_retval = CORBA_string_alloc(_ORBIT_tmpvar_5); ++ memcpy(_ORBIT_retval, _ORBIT_curptr, ++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5); ++ _ORBIT_curptr += ++ sizeof(_ORBIT_retval[_ORBIT_tmpvar_4]) * _ORBIT_tmpvar_5; ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++} +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS-user-client.c Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,92 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <orb/orbit.h> ++ ++#include "CorbaFS.h" ++ ++CorbaFS_FileSystem fs; ++ ++int ++main (int argc, char *argv[]) ++{ ++ CORBA_Environment ev; ++ CORBA_ORB orb; ++ CorbaFS_Inode inode; ++ CorbaFS_Buffer *buffer; ++ CorbaFS_DirEntSeq *dirents; ++ CorbaFS_dirent *dirent; ++ ++ CORBA_unsigned_short mode; ++ CORBA_unsigned_long uid; ++ CORBA_unsigned_long gid; ++ CORBA_unsigned_long size; ++ CORBA_unsigned_long inodeNum; ++ CORBA_unsigned_short numLinks; ++ CORBA_long atime; ++ CORBA_long mtime; ++ CORBA_long ctime; ++ ++ int i; ++ ++ int niters = 10; ++ ++ CORBA_exception_init(&ev); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); ++ ++ if(argc < 2) ++ { ++ printf("Need a binding ID thing as argv[1]\n"); ++ return 1; ++ } ++ ++ ++ fs = CORBA_ORB_string_to_object(orb, argv[1], &ev); ++ if (!fs) { ++ printf("Cannot bind to %s\n", argv[1]); ++ return 1; ++ } ++ ++ if (argc >= 3) ++ inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev); ++ else ++ inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev); ++ ++ if (!inode) ++ { ++ printf("Cannot get inode\n"); ++ } ++ ++ CorbaFS_Inode_getStatus(inode, ++ &mode, ++ &uid, ++ &gid, ++ &size, ++ &inodeNum, ++ &numLinks, ++ &atime, ++ &mtime, ++ &ctime, ++ &ev); ++ ++ printf("inode = %x\n", inode); ++ CorbaFS_Inode_readpage(inode, &buffer, 1000, 100, &ev); ++ printf("readpage got %d bytes\n", buffer->_length); ++ printf("readpage returned : %s\n", buffer->_buffer); ++ ++ if (argc >= 3) ++ dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev); ++ else ++ dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev); ++ ++ dirent = dirents->_buffer; ++ for (i = 0; i < dirents->_length; i++) ++ { ++ printf("%d = %s\n", dirent->inode, dirent->name); ++ dirent++; ++ } ++ ++ CORBA_Object_release(fs, &ev); ++ CORBA_Object_release((CORBA_Object)orb, &ev); ++ ++ return 0; ++} +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/CorbaFS.h Thu Feb 1 16:36:08 2001 +@@ -0,0 +1,349 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <glib.h> ++#define ORBIT_IDL_SERIAL 9 ++#include <orb/orbit.h> ++ ++#ifndef CorbaFS_H ++#define CorbaFS_H 1 ++#ifdef __cplusplus ++extern "C" ++{ ++#endif /* __cplusplus */ ++ ++/** typedefs **/ ++#if !defined(_CorbaFS_dirent_defined) ++#define _CorbaFS_dirent_defined 1 ++ typedef struct ++ { ++ CORBA_long inode; ++ CORBA_char *name; ++ } ++ CorbaFS_dirent; ++ ++#if !defined(TC_IMPL_TC_CorbaFS_dirent_0) ++#define TC_IMPL_TC_CorbaFS_dirent_0 'C' ++#define TC_IMPL_TC_CorbaFS_dirent_1 'o' ++#define TC_IMPL_TC_CorbaFS_dirent_2 'r' ++#define TC_IMPL_TC_CorbaFS_dirent_3 'b' ++#define TC_IMPL_TC_CorbaFS_dirent_4 'a' ++#define TC_IMPL_TC_CorbaFS_dirent_5 'F' ++#define TC_IMPL_TC_CorbaFS_dirent_6 'S' ++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_dirent_struct; ++#define TC_CorbaFS_dirent ((CORBA_TypeCode)&TC_CorbaFS_dirent_struct) ++#endif ++ extern CorbaFS_dirent *CorbaFS_dirent__alloc(void); ++ extern gpointer CorbaFS_dirent__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings); /* ORBit internal use */ ++#endif ++#if !defined(ORBIT_DECL_CORBA_sequence_CorbaFS_dirent) && !defined(_CORBA_sequence_CorbaFS_dirent_defined) ++#define ORBIT_DECL_CORBA_sequence_CorbaFS_dirent 1 ++#define _CORBA_sequence_CorbaFS_dirent_defined 1 ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_0 'C' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_1 'o' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_2 'r' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_3 'b' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_4 'a' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_5 'F' ++#define ORBIT_IMPL_CORBA_sequence_CorbaFS_dirent_6 'S' ++ typedef struct ++ { ++ CORBA_unsigned_long _maximum, ++ _length; ++ CorbaFS_dirent *_buffer; ++ CORBA_boolean _release; ++ } ++ CORBA_sequence_CorbaFS_dirent; ++#if !defined(TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0) ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_0 'C' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_1 'o' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_2 'r' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_3 'b' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_4 'a' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_5 'F' ++#define TC_IMPL_TC_CORBA_sequence_CorbaFS_dirent_6 'S' ++ extern const struct CORBA_TypeCode_struct ++ TC_CORBA_sequence_CorbaFS_dirent_struct; ++#define TC_CORBA_sequence_CorbaFS_dirent ((CORBA_TypeCode)&TC_CORBA_sequence_CorbaFS_dirent_struct) ++#endif ++ extern CORBA_sequence_CorbaFS_dirent ++ *CORBA_sequence_CorbaFS_dirent__alloc(void); ++ extern gpointer CORBA_sequence_CorbaFS_dirent__free(gpointer mem, ++ gpointer dat, ++ CORBA_boolean free_strings); /* ORBit internal use */ ++ CorbaFS_dirent *CORBA_sequence_CorbaFS_dirent_allocbuf(CORBA_unsigned_long ++ len); ++#endif ++#if !defined(_CorbaFS_DirEntSeq_defined) ++#define _CorbaFS_DirEntSeq_defined 1 ++ typedef CORBA_sequence_CorbaFS_dirent CorbaFS_DirEntSeq; ++#if !defined(TC_IMPL_TC_CorbaFS_DirEntSeq_0) ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_0 'C' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_1 'o' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_2 'r' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_3 'b' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_4 'a' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_5 'F' ++#define TC_IMPL_TC_CorbaFS_DirEntSeq_6 'S' ++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_DirEntSeq_struct; ++#define TC_CorbaFS_DirEntSeq ((CORBA_TypeCode)&TC_CorbaFS_DirEntSeq_struct) ++#endif ++ extern CorbaFS_DirEntSeq *CorbaFS_DirEntSeq__alloc(void); ++ extern gpointer CorbaFS_DirEntSeq__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings); /* ORBit internal use */ ++#endif ++#if !defined(ORBIT_DECL_CORBA_sequence_CORBA_octet) && !defined(_CORBA_sequence_CORBA_octet_defined) ++#define ORBIT_DECL_CORBA_sequence_CORBA_octet 1 ++#define _CORBA_sequence_CORBA_octet_defined 1 ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_0 'C' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_1 'o' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_2 'r' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_3 'b' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_4 'a' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_5 'F' ++#define ORBIT_IMPL_CORBA_sequence_CORBA_octet_6 'S' ++ typedef struct ++ { ++ CORBA_unsigned_long _maximum, ++ _length; ++ CORBA_octet *_buffer; ++ CORBA_boolean _release; ++ } ++ CORBA_sequence_CORBA_octet; ++#if !defined(TC_IMPL_TC_CORBA_sequence_CORBA_octet_0) ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_0 'C' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_1 'o' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_2 'r' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_3 'b' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_4 'a' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_5 'F' ++#define TC_IMPL_TC_CORBA_sequence_CORBA_octet_6 'S' ++ extern const struct CORBA_TypeCode_struct ++ TC_CORBA_sequence_CORBA_octet_struct; ++#define TC_CORBA_sequence_CORBA_octet ((CORBA_TypeCode)&TC_CORBA_sequence_CORBA_octet_struct) ++#endif ++ extern CORBA_sequence_CORBA_octet *CORBA_sequence_CORBA_octet__alloc(void); ++ extern gpointer CORBA_sequence_CORBA_octet__free(gpointer mem, ++ gpointer dat, ++ CORBA_boolean free_strings); /* ORBit internal use */ ++ CORBA_octet *CORBA_sequence_CORBA_octet_allocbuf(CORBA_unsigned_long len); ++#endif ++#if !defined(_CorbaFS_Buffer_defined) ++#define _CorbaFS_Buffer_defined 1 ++ typedef CORBA_sequence_CORBA_octet CorbaFS_Buffer; ++#if !defined(TC_IMPL_TC_CorbaFS_Buffer_0) ++#define TC_IMPL_TC_CorbaFS_Buffer_0 'C' ++#define TC_IMPL_TC_CorbaFS_Buffer_1 'o' ++#define TC_IMPL_TC_CorbaFS_Buffer_2 'r' ++#define TC_IMPL_TC_CorbaFS_Buffer_3 'b' ++#define TC_IMPL_TC_CorbaFS_Buffer_4 'a' ++#define TC_IMPL_TC_CorbaFS_Buffer_5 'F' ++#define TC_IMPL_TC_CorbaFS_Buffer_6 'S' ++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Buffer_struct; ++#define TC_CorbaFS_Buffer ((CORBA_TypeCode)&TC_CorbaFS_Buffer_struct) ++#endif ++ extern CorbaFS_Buffer *CorbaFS_Buffer__alloc(void); ++ extern gpointer CorbaFS_Buffer__free(gpointer mem, gpointer dat, ++ CORBA_boolean free_strings); /* ORBit internal use */ ++#endif ++#if !defined(ORBIT_DECL_CorbaFS_Inode) && !defined(_CorbaFS_Inode_defined) ++#define ORBIT_DECL_CorbaFS_Inode 1 ++#define _CorbaFS_Inode_defined 1 ++#define CorbaFS_Inode__free CORBA_Object__free ++ typedef CORBA_Object CorbaFS_Inode; ++ extern CORBA_unsigned_long CorbaFS_Inode__classid; ++#if !defined(TC_IMPL_TC_CorbaFS_Inode_0) ++#define TC_IMPL_TC_CorbaFS_Inode_0 'C' ++#define TC_IMPL_TC_CorbaFS_Inode_1 'o' ++#define TC_IMPL_TC_CorbaFS_Inode_2 'r' ++#define TC_IMPL_TC_CorbaFS_Inode_3 'b' ++#define TC_IMPL_TC_CorbaFS_Inode_4 'a' ++#define TC_IMPL_TC_CorbaFS_Inode_5 'F' ++#define TC_IMPL_TC_CorbaFS_Inode_6 'S' ++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_Inode_struct; ++#define TC_CorbaFS_Inode ((CORBA_TypeCode)&TC_CorbaFS_Inode_struct) ++#endif ++#endif ++#if !defined(ORBIT_DECL_CorbaFS_FileSystem) && !defined(_CorbaFS_FileSystem_defined) ++#define ORBIT_DECL_CorbaFS_FileSystem 1 ++#define _CorbaFS_FileSystem_defined 1 ++#define CorbaFS_FileSystem__free CORBA_Object__free ++ typedef CORBA_Object CorbaFS_FileSystem; ++ extern CORBA_unsigned_long CorbaFS_FileSystem__classid; ++#if !defined(TC_IMPL_TC_CorbaFS_FileSystem_0) ++#define TC_IMPL_TC_CorbaFS_FileSystem_0 'C' ++#define TC_IMPL_TC_CorbaFS_FileSystem_1 'o' ++#define TC_IMPL_TC_CorbaFS_FileSystem_2 'r' ++#define TC_IMPL_TC_CorbaFS_FileSystem_3 'b' ++#define TC_IMPL_TC_CorbaFS_FileSystem_4 'a' ++#define TC_IMPL_TC_CorbaFS_FileSystem_5 'F' ++#define TC_IMPL_TC_CorbaFS_FileSystem_6 'S' ++ extern const struct CORBA_TypeCode_struct TC_CorbaFS_FileSystem_struct; ++#define TC_CorbaFS_FileSystem ((CORBA_TypeCode)&TC_CorbaFS_FileSystem_struct) ++#endif ++#endif ++ ++/** POA structures **/ ++ typedef struct ++ { ++ void *_private; ++ void (*getStatus) (PortableServer_Servant _servant, ++ CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, CORBA_long * atime, ++ CORBA_long * mtime, CORBA_long * ctime, ++ CORBA_Environment * ev); ++ void (*readpage) (PortableServer_Servant _servant, ++ CorbaFS_Buffer ** buffer, const CORBA_long size, ++ const CORBA_long offset, CORBA_Environment * ev); ++ void (*release) (PortableServer_Servant _servant, ++ CORBA_Environment * ev); ++ } ++ POA_CorbaFS_Inode__epv; ++ typedef struct ++ { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_CorbaFS_Inode__epv *CorbaFS_Inode_epv; ++ } ++ POA_CorbaFS_Inode__vepv; ++ typedef struct ++ { ++ void *_private; ++ POA_CorbaFS_Inode__vepv *vepv; ++ } ++ POA_CorbaFS_Inode; ++ extern void POA_CorbaFS_Inode__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ extern void POA_CorbaFS_Inode__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ typedef struct ++ { ++ void *_private; ++ ++ CorbaFS_Inode(*getInode) (PortableServer_Servant _servant, ++ const CORBA_char * path, ++ CORBA_Environment * ev); ++ CorbaFS_DirEntSeq *(*readdir) (PortableServer_Servant _servant, ++ const CORBA_char * path, ++ CORBA_Environment * ev); ++ CORBA_char *(*readlink) (PortableServer_Servant _servant, ++ const CORBA_char * filename, ++ CORBA_Environment * ev); ++ } ++ POA_CorbaFS_FileSystem__epv; ++ typedef struct ++ { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_CorbaFS_FileSystem__epv *CorbaFS_FileSystem_epv; ++ } ++ POA_CorbaFS_FileSystem__vepv; ++ typedef struct ++ { ++ void *_private; ++ POA_CorbaFS_FileSystem__vepv *vepv; ++ } ++ POA_CorbaFS_FileSystem; ++ extern void POA_CorbaFS_FileSystem__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ extern void POA_CorbaFS_FileSystem__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ ++/** prototypes **/ ++ void CorbaFS_Inode_getStatus(CorbaFS_Inode _obj, ++ CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, ++ CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, ++ CORBA_long * atime, CORBA_long * mtime, ++ CORBA_long * ctime, CORBA_Environment * ev); ++ void CorbaFS_Inode_readpage(CorbaFS_Inode _obj, CorbaFS_Buffer ** buffer, ++ const CORBA_long size, const CORBA_long offset, ++ CORBA_Environment * ev); ++ void CorbaFS_Inode_release(CorbaFS_Inode _obj, CORBA_Environment * ev); ++ CorbaFS_Inode CorbaFS_FileSystem_getInode(CorbaFS_FileSystem _obj, ++ const CORBA_char * path, ++ CORBA_Environment * ev); ++ CorbaFS_DirEntSeq *CorbaFS_FileSystem_readdir(CorbaFS_FileSystem _obj, ++ const CORBA_char * path, ++ CORBA_Environment * ev); ++ CORBA_char *CorbaFS_FileSystem_readlink(CorbaFS_FileSystem _obj, ++ const CORBA_char * filename, ++ CORBA_Environment * ev); ++ ++ void _ORBIT_skel_CorbaFS_Inode_getStatus(POA_CorbaFS_Inode * ++ _ORBIT_servant, ++ GIOPRecvBuffer * ++ _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ void (*_impl_getStatus) ++ (PortableServer_Servant _servant, ++ CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, ++ CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, ++ CORBA_long * atime, ++ CORBA_long * mtime, ++ CORBA_long * ctime, ++ CORBA_Environment * ev)); ++ void _ORBIT_skel_CorbaFS_Inode_readpage(POA_CorbaFS_Inode * _ORBIT_servant, ++ GIOPRecvBuffer * ++ _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ void (*_impl_readpage) ++ (PortableServer_Servant _servant, ++ CorbaFS_Buffer ** buffer, ++ const CORBA_long size, ++ const CORBA_long offset, ++ CORBA_Environment * ev)); ++ void _ORBIT_skel_CorbaFS_Inode_release(POA_CorbaFS_Inode * _ORBIT_servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ void (*_impl_release) ++ (PortableServer_Servant _servant, ++ CORBA_Environment * ev)); ++ void _ORBIT_skel_CorbaFS_FileSystem_getInode(POA_CorbaFS_FileSystem * ++ _ORBIT_servant, ++ GIOPRecvBuffer * ++ _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ CorbaFS_Inode(*_impl_getInode) ++ (PortableServer_Servant ++ _servant, ++ const CORBA_char * path, ++ CORBA_Environment * ev)); ++ void _ORBIT_skel_CorbaFS_FileSystem_readdir(POA_CorbaFS_FileSystem * ++ _ORBIT_servant, ++ GIOPRecvBuffer * ++ _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ CorbaFS_DirEntSeq * ++ (*_impl_readdir) ++ (PortableServer_Servant ++ _servant, ++ const CORBA_char * path, ++ CORBA_Environment * ev)); ++ void _ORBIT_skel_CorbaFS_FileSystem_readlink(POA_CorbaFS_FileSystem * ++ _ORBIT_servant, ++ GIOPRecvBuffer * ++ _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ CORBA_char * ++ (*_impl_readlink) ++ (PortableServer_Servant ++ _servant, ++ const CORBA_char * filename, ++ CORBA_Environment * ev)); ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif ++#undef ORBIT_IDL_SERIAL +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,20 @@ ++# ++# Makefile for KORBit CorbaFS client ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-corbafs-client.o ++ ++obj-y := CorbaFS-common.o CorbaFS-stubs.o CorbaFS-client.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++CorbaFS-client.c: CorbaFS.h ++ ++CorbaFS.h CorbaFS-common.c CorbaFS-stubs.c: ../CorbaFS.idl ++ $(ORBIT_IDL) --noskels ../CorbaFS.idl +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/Makefile.user Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/Makefile.user Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = CorbaFS ++ ++CFLAGS = -Wall `orbit-config --cflags client` -I../../.. ++LDFLAGS = `orbit-config --libs client` ++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-user-client.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-user-client: $(OBJS) ++ gcc -o $(PROJECT)-user-client $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-user-client.o: $(PROJECT).h ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-user-client ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-skels.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/client/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README +--- linux-2.4.1/net/korbit/modules/CorbaFS/client/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/client/README Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,4 @@ ++This module implements the kernel VFS->kORBit interface. This is called a 'client' ++because it actually USES a CORBA object that is exported from someplace else. ++ ++ORB: kORBit +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Entries Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,6 @@ ++/CorbaFS-server.c/1.8/Thu Feb 1 09:47:03 2001// ++/CorbaFS-skelimpl.c/1.10/Thu Feb 1 09:47:04 2001// ++/Makefile/1.5/Thu Feb 1 09:47:04 2001// ++/README/1.2/Thu Feb 1 09:47:04 2001// ++/RunServer.sh/1.1/Thu Feb 1 09:47:04 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Repository Thu Feb 1 11:47:03 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CVS/Root Thu Feb 1 11:47:03 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-server.c Thu Feb 1 11:47:03 2001 +@@ -0,0 +1,37 @@ ++#include <stdio.h> ++#include "CorbaFS-skelimpl.c" ++ ++CORBA_ORB orb; ++PortableServer_POA poa; ++CORBA_Environment *ev; ++PortableServer_ObjectId *objid; ++ ++int main(int argc, char *argv[]) { ++ CorbaFS_FileSystem fs; ++ impl_POA_CorbaFS_FileSystem *fs_impl; ++ ++ PortableServer_POAManager pm; ++ ev = g_new0(CORBA_Environment,1); ++ ++ CORBA_exception_init(ev); ++ printf("Make sure you use TCP/IP and not Unix sockets!\n"); ++ ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ poa = (PortableServer_POA) ++ CORBA_ORB_resolve_initial_references(orb, ++ "RootPOA", ++ ev); ++ fs = impl_CorbaFS_FileSystem__create(poa, ev); ++ ++ pm = PortableServer_POA__get_the_POAManager(poa, ev); ++ PortableServer_POAManager_activate(pm, ev); ++ ++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev ); ++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev ); ++ ++ printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev)); ++ ++ CORBA_ORB_run(orb, ev); ++ ++ return 0; ++} +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/CorbaFS-skelimpl.c Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,353 @@ ++#include <sys/param.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <fcntl.h> ++#include <dirent.h> ++ ++#include "CorbaFS.h" ++ ++/*** App-specific servant structures ***/ ++ ++#define printf(fmt, args...) fprintf(stderr, fmt, ##args); ++ ++typedef struct ++{ ++ POA_CorbaFS_Inode servant; ++ PortableServer_POA poa; ++ ++ CORBA_char *path; ++#if 0 ++ CORBA_unsigned_short mode; ++ CORBA_unsigned_long uid; ++ CORBA_unsigned_long gid; ++ CORBA_unsigned_long size; ++ CORBA_unsigned_long inodeNum; ++ CORBA_unsigned_short numLinks; ++ CORBA_long atime; ++ CORBA_long mtime; ++ CORBA_long ctime; ++#endif ++} ++impl_POA_CorbaFS_Inode; ++ ++typedef struct ++{ ++ POA_CorbaFS_FileSystem servant; ++ PortableServer_POA poa; ++ ++} ++impl_POA_CorbaFS_FileSystem; ++ ++/*** Implementation stub prototypes ***/ ++ ++static void impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant, ++ CORBA_Environment * ev); ++static void ++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant, ++ CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, ++ CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, ++ CORBA_long * atime, ++ CORBA_long * mtime, ++ CORBA_long * ctime, CORBA_Environment * ev); ++ ++static void ++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant, ++ CorbaFS_Buffer ** buffer, ++ CORBA_long size, ++ CORBA_long offset, CORBA_Environment * ev); ++ ++static void ++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant, ++ CORBA_Environment * ev); ++ ++static void impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * ++ servant, CORBA_Environment * ev); ++static CorbaFS_Inode ++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * path, CORBA_Environment * ev); ++ ++static CorbaFS_DirEntSeq ++ *impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * path, ++ ++ CORBA_Environment * ev); ++ ++static CORBA_char ++ *impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * filename, ++ CORBA_Environment * ev); ++ ++/*** epv structures ***/ ++ ++static PortableServer_ServantBase__epv impl_CorbaFS_Inode_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_CorbaFS_Inode__epv impl_CorbaFS_Inode_epv = { ++ NULL, /* _private */ ++ (gpointer) & impl_CorbaFS_Inode_getStatus, ++ ++ (gpointer) & impl_CorbaFS_Inode_readpage, ++ ++ (gpointer) & impl_CorbaFS_Inode_release, ++ ++}; ++static PortableServer_ServantBase__epv impl_CorbaFS_FileSystem_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_CorbaFS_FileSystem__epv impl_CorbaFS_FileSystem_epv = { ++ NULL, /* _private */ ++ (gpointer) & impl_CorbaFS_FileSystem_getInode, ++ ++ (gpointer) & impl_CorbaFS_FileSystem_readdir, ++ ++ (gpointer) & impl_CorbaFS_FileSystem_readlink, ++ ++}; ++ ++/*** vepv structures ***/ ++ ++static POA_CorbaFS_Inode__vepv impl_CorbaFS_Inode_vepv = { ++ &impl_CorbaFS_Inode_base_epv, ++ &impl_CorbaFS_Inode_epv, ++}; ++static POA_CorbaFS_FileSystem__vepv impl_CorbaFS_FileSystem_vepv = { ++ &impl_CorbaFS_FileSystem_base_epv, ++ &impl_CorbaFS_FileSystem_epv, ++}; ++ ++/*** Stub implementations ***/ ++ ++static CorbaFS_Inode ++impl_CorbaFS_Inode__create(PortableServer_POA poa, CORBA_Environment * ev) ++{ ++ CorbaFS_Inode retval; ++ impl_POA_CorbaFS_Inode *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_CorbaFS_Inode, 1); ++ newservant->servant.vepv = &impl_CorbaFS_Inode_vepv; ++ newservant->poa = poa; ++ POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static void ++impl_CorbaFS_Inode__destroy(impl_POA_CorbaFS_Inode * servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static void ++impl_CorbaFS_Inode_getStatus(impl_POA_CorbaFS_Inode * servant, ++ CORBA_unsigned_short * mode, ++ CORBA_unsigned_long * uid, ++ CORBA_unsigned_long * gid, ++ CORBA_unsigned_long * size, ++ CORBA_unsigned_long * inodeNum, ++ CORBA_unsigned_short * numLinks, ++ CORBA_long * atime, ++ CORBA_long * mtime, ++ CORBA_long * ctime, CORBA_Environment * ev) ++{ ++ struct stat buf; ++ ++ printf("Inode_getStatus()\n"); ++ printf("Inode path = %s\n", servant->path); ++ lstat(servant->path, &buf); ++ ++ *mode = buf.st_mode; ++ *uid = buf.st_uid; ++ *gid = buf.st_gid; ++ *size = buf.st_size; ++ *inodeNum = buf.st_ino; ++ *numLinks = buf.st_nlink; ++ *atime = buf.st_atime; ++ *mtime = buf.st_mtime; ++ *ctime = buf.st_ctime; ++} ++ ++static void ++impl_CorbaFS_Inode_readpage(impl_POA_CorbaFS_Inode * servant, ++ CorbaFS_Buffer ** buffer, ++ CORBA_long size, ++ CORBA_long offset, CORBA_Environment * ev) ++{ ++ int fd = -1, c = 0; ++ ++ printf("Inode_readpage(buffer, %d, %d)\n", size, offset); ++ printf("Inode_readpage : path = %s\n", servant->path); ++ ++ *buffer = CorbaFS_Buffer__alloc(); ++ (*buffer)->_maximum = size; ++ (*buffer)->_buffer = CORBA_octet_allocbuf(size); ++ ++ memset((*buffer)->_buffer, size, 0); ++ ++ fd = open(servant->path, O_RDONLY); ++ printf("Inode_readpage : fd = %d\n", fd); ++ lseek(fd, offset, SEEK_SET); ++ c = read(fd, (*buffer)->_buffer, size); ++ printf("Inode_readpage : read %d bytes\n", c); ++ (*buffer)->_length = c; ++ close(fd); ++} ++ ++static void ++impl_CorbaFS_Inode_release(impl_POA_CorbaFS_Inode * servant, ++ CORBA_Environment * ev) ++{ ++ printf("Inode_release()\n"); ++} ++ ++static CorbaFS_FileSystem ++impl_CorbaFS_FileSystem__create(PortableServer_POA poa, ++ CORBA_Environment * ev) ++{ ++ CorbaFS_FileSystem retval; ++ impl_POA_CorbaFS_FileSystem *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1); ++ newservant->servant.vepv = &impl_CorbaFS_FileSystem_vepv; ++ newservant->poa = poa; ++ POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static void ++impl_CorbaFS_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static CorbaFS_Inode ++impl_CorbaFS_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * path, CORBA_Environment * ev) ++{ ++ CorbaFS_Inode retval; ++ impl_POA_CorbaFS_Inode *inode; ++ ++ printf("FileSystem_getInode(%s)\n", path); ++ ++ retval = impl_CorbaFS_Inode__create(servant->poa, ev); ++ ++ inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev ); ++ inode->path = CORBA_string_dup(path); ++#if 0 ++ inode->mode = 0040777; /* world-readable directory */ ++ inode->uid = 0; ++ inode->gid = 0; ++ inode->size = 4096; ++ inode->inodeNum = inodeNum++; ++ inode->numLinks = 1; ++ inode->atime = 0; ++ inode->mtime = 100; ++ inode->ctime = 10000; ++#endif ++ ++ return retval; ++} ++ ++static CorbaFS_DirEntSeq * ++impl_CorbaFS_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * path, CORBA_Environment * ev) ++{ ++ CorbaFS_DirEntSeq *retval; ++ CorbaFS_dirent *dirent; ++ ++ DIR *dir; ++ struct dirent *dirp; ++ int c; ++ ++ printf("FileSystem_readdir(%s)\n", path); ++ ++ retval = CorbaFS_DirEntSeq__alloc(); ++ retval->_maximum = 0; ++ retval->_length = 0; ++ ++ dir = opendir(path); ++ if (dir == NULL) ++ return retval; ++ ++ c = 0; ++ while ((dirp = readdir(dir))) ++ c++; ++ ++ rewinddir(dir); ++ ++ printf("%d directories\n", c); ++ ++ retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(c); ++ retval->_maximum = c; ++ dirent = retval->_buffer; ++ ++ c = 0; ++ while ((dirp = readdir(dir)) && (c < retval->_maximum)) ++ { ++ printf("Adding directory %d : %s (%d)\n", c, dirp->d_name, dirp->d_ino); ++ ++ dirent[c].inode = dirp->d_ino; ++ dirent[c].name = CORBA_string_dup(dirp->d_name); ++ c++; ++ } ++ retval->_length = c; ++ ++ closedir(dir); ++ ++ return retval; ++} ++ ++static CORBA_char * ++impl_CorbaFS_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant, ++ CORBA_char * filename, ++ CORBA_Environment * ev) ++{ ++ CORBA_char *retval = CORBA_OBJECT_NIL; ++ char tmp[MAXPATHLEN + 1]; ++ int len; ++ ++ printf("FileSystem_readlink(%s) = ", filename); ++ len = readlink(filename, tmp, MAXPATHLEN); ++ if (len != -1) ++ { ++ tmp[len] = '\0'; ++ retval = CORBA_string_dup(tmp); ++ } ++ ++ printf("%s\n", retval); ++ ++ return retval; ++} +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/Makefile Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = CorbaFS ++ ++CFLAGS = -Wall `orbit-config --cflags server` -I../../.. ++LDFLAGS = `orbit-config --libs server` ++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-server: $(OBJS) ++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-server.o: $(PROJECT).h $(PROJECT)-skelimpl.c ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-server ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-skels.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/README Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,8 @@ ++This server provides an NFS like capability of exporting an existing filesystem. ++ ++ORB: ORBit ++Status: Working! (for readonly fs's) ++ ++NOTE!!!!: When starting this server make sure you pass ORBit the options to ++ have it use ipv4 sockets and not unix domain sockets, or else bad ++ things will happen. You can use the included RunServer script. +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh +--- linux-2.4.1/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server/RunServer.sh Thu Feb 1 11:47:04 2001 +@@ -0,0 +1 @@ ++./CorbaFS-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1 +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries +--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Entries Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,3 @@ ++/PerlServer/1.2/Thu Feb 1 09:47:04 2001// ++/README/1.1/Thu Feb 1 09:47:04 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository +--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Repository Thu Feb 1 11:47:04 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/CorbaFS/server-perl +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root +--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/CVS/Root Thu Feb 1 11:47:04 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer +--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/PerlServer Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,67 @@ ++#!/usr/bin/perl -w ++use CORBA::ORBit idl => [ qw(../CorbaFS.idl) ]; ++use Error qw(:try); ++use strict; ++ ++ ++package MyFSInode; ++@MyFSInode::ISA = qw(POA_CorbaFS::Inode); ++ ++sub new { ++ my $self = bless { name => shift }; ++ print "INODE CREATED: $self->{name}!\n"; ++} ++ ++sub getStatus { ++ my ($self) = @_; ++ print "$self->getStatus()\n"; ++} ++ ++sub readpage { ++ return ""; ++} ++ ++sub release { ++} ++ ++ ++package MyFileSystem; ++@MyFileSystem::ISA = qw(POA_CorbaFS::FileSystem); ++ ++sub new { ++ my $self = bless { root => '/home' }; ++} ++ ++sub getInode { ++ my $path = shift; ++ print "getInode($path)\n"; ++ return new MyFSInode($path); ++} ++ ++sub readdir { ++ my $path = shift; ++ print "readdir($path)\n"; ++ return [ { inode => 1, name => '...' } ]; ++} ++ ++sub readlink { ++ my $path = shift; ++ print "readlink($path)\n"; ++ return "fredrik"; ++} ++ ++ ++package Main; ++ ++my $orb = CORBA::ORB_init("orbit-local-orb"); ++my $poa = $orb->resolve_initial_references("RootPOA"); ++ ++my $Server = new MyFileSystem(); ++my $id = $poa->activate_object($Server); ++my $ref = $orb->object_to_string($poa->id_to_reference($id)); ++ ++print "$ref\n"; ++ ++print "Running orb:\n"; ++$orb->run(); ++exit(0); +diff -urN linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README +--- linux-2.4.1/net/korbit/modules/CorbaFS/server-perl/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/CorbaFS/server-perl/README Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,4 @@ ++Test filesystem implementation in Perl. ++ ++ORB: ORBit/Perl ++Status: horribly broken +diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,4 @@ ++/Makefile/1.3/Thu Feb 1 09:47:04 2001// ++/README/1.1/Thu Feb 1 09:47:05 2001// ++/echo.idl/1.1/Thu Feb 1 09:47:05 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/Echo/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Entries.Log Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,3 @@ ++A D/client//// ++A D/client-perl//// ++A D/server//// +diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Echo/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Repository Thu Feb 1 11:47:04 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Echo +diff -urN linux-2.4.1/net/korbit/modules/Echo/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root +--- linux-2.4.1/net/korbit/modules/Echo/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/CVS/Root Thu Feb 1 11:47:04 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Echo/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile +--- linux-2.4.1/net/korbit/modules/Echo/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/Makefile Thu Feb 1 11:47:04 2001 +@@ -0,0 +1,11 @@ ++# ++# Makefile for KORBit/modules/Console ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_ECHO) := client server ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/Echo/README linux-2.4.1-korbit/net/korbit/modules/Echo/README +--- linux-2.4.1/net/korbit/modules/Echo/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/README Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,2 @@ ++The Echo test is very similar to the console test, but it also "returns" a ++"random" number. The random number, in our case, is simply a constant. +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Entries Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,6 @@ ++/Makefile/1.4/Thu Feb 1 09:47:05 2001// ++/Makefile.user/1.1/Thu Feb 1 09:47:05 2001// ++/README/1.1/Thu Feb 1 09:47:05 2001// ++/RunClient.sh/1.1/Thu Feb 1 09:47:05 2001// ++/echo-client.c/1.6/Thu Feb 1 09:47:05 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Repository Thu Feb 1 11:47:05 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Echo/client +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root +--- linux-2.4.1/net/korbit/modules/Echo/client/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/CVS/Root Thu Feb 1 11:47:05 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile +--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,20 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-echo-client.o ++ ++obj-y := echo-common.o echo-stubs.o echo-client.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++echo-client.c: echo.h ++ ++echo.h echo-common.c echo-stubs.c: ../echo.idl ++ $(ORBIT_IDL) --noskels ../echo.idl +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user +--- linux-2.4.1/net/korbit/modules/Echo/client/Makefile.user Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/Makefile.user Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = echo ++ ++CFLAGS = -Wall `orbit-config --cflags client` -I../../.. ++LDFLAGS = `orbit-config --libs client` ++OBJS = $(PROJECT)-common.o $(PROJECT)-stubs.o $(PROJECT)-client.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-client: $(OBJS) ++ gcc -o $(PROJECT)-client $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-client.c: $(PROJECT).h ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-stubs.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --noskels ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-client ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-stubs.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/README linux-2.4.1-korbit/net/korbit/modules/Echo/client/README +--- linux-2.4.1/net/korbit/modules/Echo/client/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/README Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,4 @@ ++This simply tests the Echo service. ++ ++ORB: ORBit ++Status: working +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh +--- linux-2.4.1/net/korbit/modules/Echo/client/RunClient.sh Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/RunClient.sh Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,3 @@ ++#!/bin/sh ++date ++./echo-client `cat /proc/corba/echo-server` 5 +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c +--- linux-2.4.1/net/korbit/modules/Echo/client/echo-client.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-client.c Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,119 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/time.h> ++#include <unistd.h> ++#include <orb/orbit.h> ++ ++#ifdef __KERNEL__ ++#include <linux/init.h> ++#include <linux/module.h> ++#include "korbit.h" ++#endif ++#include "echo.h" ++ ++Echo echo_client, bec; ++ ++#define BATCH_SIZE 1 ++ ++ ++#ifndef __KERNEL__ ++int main (int argc, char *argv[]) { ++#else ++int __init corba_echo_init(void) { ++ int argc = 1; char *argv[] = { "echo-client", 0, 0 }; ++#endif ++ CORBA_Environment ev; ++ CORBA_ORB orb; ++ CORBA_long rv; ++ char buf[30]; ++ int i, j; ++ ++ int niters = 5; ++ ++#ifndef __KERNEL__ ++ struct timeval start, end; ++ long diff, diffsum = 0; ++#endif ++ ++ CORBA_exception_init(&ev); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); ++ ++#ifdef __KERNEL__ ++ { ++ int c, fd = open("/tmp/echo-ior", O_RDONLY, 0); ++ if (fd == -1) ++ return -1; ++ printf("Reading IOR from /tmp/echo-ior\n"); ++ argv[1] = malloc(501); ++ c = read(fd, argv[1], 500); ++ argv[1][c] = '\0'; ++ printf("Reading %d bytes: %s\n", c, argv[1]); ++ } ++#else ++ if(argc < 2) ++ { ++ printf("Need an IOR as argv[1]\n"); ++ return 1; ++ } ++ ++ if(argc == 3) ++ niters = atoi(argv[2]); ++#endif ++ ++ echo_client = CORBA_ORB_string_to_object(orb, argv[1], &ev); ++ if (!echo_client) { ++ printf("Cannot bind to %s\n", argv[1]); ++ return 1; ++ } ++ ++ for(i = 0; i < niters; i++) { ++ g_snprintf(buf, sizeof(buf), "Hello, world [%d]", i); ++#ifdef __KERNEL__ ++ bec = Echo_echoString(echo_client, buf, &rv, &ev); ++#else ++ gettimeofday(&start, NULL); ++ for (j = BATCH_SIZE; j > 0; j--) { ++ bec = Echo_echoString(echo_client, buf, &rv, &ev); ++ if (j != 1) CORBA_Object_release(bec, &ev); ++ } ++ gettimeofday(&end, NULL); ++ diff = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); ++ diff /= BATCH_SIZE; ++ diffsum += diff; ++ ++ printf("duration = %d usec\t", diff); ++#endif ++ ++ if(ev._major != CORBA_NO_EXCEPTION) { ++ printf("\nWe got exception %d from echoString!\n", ev._major); ++ return 1; ++ } ++ ++ CORBA_Object_release(echo_client, &ev); ++ if(ev._major != CORBA_NO_EXCEPTION) { ++ printf("we got exception %d from release!\n", ev._major); ++ return 1; ++ } ++ ++ printf("[client] %d\n", rv); ++ ++ echo_client = bec; bec = CORBA_OBJECT_NIL; ++ } ++ ++#ifndef __KERNEL__ ++ printf("duration average = %d usec\n", diffsum / niters); ++ CORBA_Object_release(echo_client, &ev); ++ CORBA_Object_release((CORBA_Object)orb, &ev); ++#endif ++ ++ return 0; ++} ++ ++ ++#ifdef __KERNEL__ ++void corba_echo_exit(void) { ++} ++ ++module_init(corba_echo_init) ++module_exit(corba_echo_exit) ++#endif +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c +--- linux-2.4.1/net/korbit/modules/Echo/client/echo-common.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-common.c Thu Feb 1 16:36:36 2001 +@@ -0,0 +1,27 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "echo.h" ++ ++#if ( (TC_IMPL_TC_Echo_0 == 'e') \ ++&& (TC_IMPL_TC_Echo_1 == 'c') \ ++&& (TC_IMPL_TC_Echo_2 == 'h') \ ++&& (TC_IMPL_TC_Echo_3 == 'o') \ ++) && !defined(TC_DEF_TC_Echo) ++#define TC_DEF_TC_Echo 1 ++const struct CORBA_TypeCode_struct TC_Echo_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0", ++ 0, 0, ++ NULL, ++ NULL, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++CORBA_unsigned_long Echo__classid = 0; +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c +--- linux-2.4.1/net/korbit/modules/Echo/client/echo-stubs.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo-stubs.c Thu Feb 1 16:36:36 2001 +@@ -0,0 +1,134 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "echo.h" ++ ++Echo ++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ Echo _ORBIT_retval; ++ ++ if (_obj->servant && _obj->vepv && Echo__classid) { ++ _ORBIT_retval = ++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj-> ++ servant, ++ astring, ++ anum, ev); ++ return _ORBIT_retval; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[11]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 11, "echoString"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 15 }; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(astring) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ { ++ guchar *_ORBIT_t; ++ ++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1)); ++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), (_ORBIT_t), ++ sizeof(_ORBIT_tmpvar_1)); ++ } ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ (astring), ++ sizeof(astring[_ORBIT_tmpvar_0]) * ++ _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & ((*anum)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*anum) = *((CORBA_long *) _ORBIT_curptr); ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++} +diff -urN linux-2.4.1/net/korbit/modules/Echo/client/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h +--- linux-2.4.1/net/korbit/modules/Echo/client/echo.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client/echo.h Thu Feb 1 16:36:36 2001 +@@ -0,0 +1,77 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <glib.h> ++#define ORBIT_IDL_SERIAL 9 ++#include <orb/orbit.h> ++ ++#ifndef echo_H ++#define echo_H 1 ++#ifdef __cplusplus ++extern "C" ++{ ++#endif /* __cplusplus */ ++ ++/** typedefs **/ ++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined) ++#define ORBIT_DECL_Echo 1 ++#define _Echo_defined 1 ++#define Echo__free CORBA_Object__free ++ typedef CORBA_Object Echo; ++ extern CORBA_unsigned_long Echo__classid; ++#if !defined(TC_IMPL_TC_Echo_0) ++#define TC_IMPL_TC_Echo_0 'e' ++#define TC_IMPL_TC_Echo_1 'c' ++#define TC_IMPL_TC_Echo_2 'h' ++#define TC_IMPL_TC_Echo_3 'o' ++ extern const struct CORBA_TypeCode_struct TC_Echo_struct; ++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct) ++#endif ++#endif ++ ++/** POA structures **/ ++ typedef struct ++ { ++ void *_private; ++ ++ Echo(*echoString) (PortableServer_Servant _servant, ++ const CORBA_char * astring, CORBA_long * anum, ++ CORBA_Environment * ev); ++ } ++ POA_Echo__epv; ++ typedef struct ++ { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_Echo__epv *Echo_epv; ++ } ++ POA_Echo__vepv; ++ typedef struct ++ { ++ void *_private; ++ POA_Echo__vepv *vepv; ++ } ++ POA_Echo; ++ extern void POA_Echo__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ extern void POA_Echo__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ ++/** prototypes **/ ++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring, ++ CORBA_long * anum, CORBA_Environment * ev); ++ ++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ Echo(*_impl_echoString) ++ (PortableServer_Servant _servant, ++ const CORBA_char * astring, ++ CORBA_long * anum, ++ CORBA_Environment * ev)); ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif ++#undef ORBIT_IDL_SERIAL +diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Entries Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,3 @@ ++/PerlTest/1.2/Thu Feb 1 09:47:06 2001// ++/README/1.1/Thu Feb 1 09:47:06 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Repository Thu Feb 1 11:47:06 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Echo/client-perl +diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root +--- linux-2.4.1/net/korbit/modules/Echo/client-perl/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/CVS/Root Thu Feb 1 11:47:06 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest +--- linux-2.4.1/net/korbit/modules/Echo/client-perl/PerlTest Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/PerlTest Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,17 @@ ++#!/usr/bin/perl -w ++ ++use CORBA::ORBit idl => [ qw(../echo.idl) ]; ++use Error qw(:try); ++use strict; ++ ++my $orb = CORBA::ORB_init("orbit-local-orb"); ++open IOR, "/proc/corba/echo-server" or die "no console server found!"; ++my $ior = <IOR>; ++close IOR; ++chomp($ior); # Kill fredrik's newline... ++ ++my $echo = $orb->string_to_object($ior); ++# Echo echoString(in string astring, out long anum); ++my ($echo2, $num) = $echo->echoString("Echo Strange World"); ++ ++print "Return Echo = $echo2\nnum = $num\n"; +diff -urN linux-2.4.1/net/korbit/modules/Echo/client-perl/README linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README +--- linux-2.4.1/net/korbit/modules/Echo/client-perl/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/client-perl/README Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,4 @@ ++Another test of the echo server. ++ ++ORB: ORBit/Perl ++Status: Working fine +diff -urN linux-2.4.1/net/korbit/modules/Echo/echo.idl linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl +--- linux-2.4.1/net/korbit/modules/Echo/echo.idl Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/echo.idl Thu Feb 1 11:47:05 2001 +@@ -0,0 +1,3 @@ ++interface Echo { ++ Echo echoString(in string astring, out long anum); ++}; +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries +--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Entries Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,6 @@ ++/Makefile/1.2/Thu Feb 1 09:47:06 2001// ++/Makefile.user/1.3/Thu Feb 1 09:47:06 2001// ++/README/1.1/Thu Feb 1 09:47:06 2001// ++/RunServer.sh/1.1/Thu Feb 1 09:47:06 2001// ++/echo-server.c/1.8/Thu Feb 1 09:47:06 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository +--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Repository Thu Feb 1 11:47:06 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/Echo/server +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root +--- linux-2.4.1/net/korbit/modules/Echo/server/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/CVS/Root Thu Feb 1 11:47:06 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile +--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,21 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-echo-server.o ++ ++obj-y := echo-server.o echo-skels.o echo-common.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++echo-server.c: echo.h echo-skels.c ++ ++ ++echo.h echo-common.c echo-skels.c: ../echo.idl ++ $(ORBIT_IDL) ../echo.idl +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user +--- linux-2.4.1/net/korbit/modules/Echo/server/Makefile.user Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/Makefile.user Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,27 @@ ++# ++# Makefile for user level server ++# ++ ++PROJECT = echo ++ ++CFLAGS = -Wall `orbit-config --cflags server` -I../../.. ++LDFLAGS = `orbit-config --libs server` ++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-server: $(OBJS) ++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-server.c: $(PROJECT).h ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-server ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-skels.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/README linux-2.4.1-korbit/net/korbit/modules/Echo/server/README +--- linux-2.4.1/net/korbit/modules/Echo/server/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/README Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,5 @@ ++This server implements the kernel side interface in terms of printk. ++ ++This server also builds in user space with ORBit. Build with ++ make -f Makefile.user ++ +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh +--- linux-2.4.1/net/korbit/modules/Echo/server/RunServer.sh Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/RunServer.sh Thu Feb 1 11:47:06 2001 +@@ -0,0 +1 @@ ++./echo-server -ORBIIOPUSock=0 -ORBIIOPIPv4=1 +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c +--- linux-2.4.1/net/korbit/modules/Echo/server/echo-common.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-common.c Thu Feb 1 16:36:57 2001 +@@ -0,0 +1,27 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "echo.h" ++ ++#if ( (TC_IMPL_TC_Echo_0 == 'e') \ ++&& (TC_IMPL_TC_Echo_1 == 'c') \ ++&& (TC_IMPL_TC_Echo_2 == 'h') \ ++&& (TC_IMPL_TC_Echo_3 == 'o') \ ++) && !defined(TC_DEF_TC_Echo) ++#define TC_DEF_TC_Echo 1 ++const struct CORBA_TypeCode_struct TC_Echo_struct = { ++ ++ {{(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ++ ORBIT_PSEUDO_TYPECODE}, ++ ++ CORBA_tk_objref, "Echo", "IDL:Echo:1.0", ++ 0, 0, ++ NULL, ++ NULL, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++CORBA_unsigned_long Echo__classid = 0; +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c +--- linux-2.4.1/net/korbit/modules/Echo/server/echo-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-server.c Thu Feb 1 11:47:06 2001 +@@ -0,0 +1,103 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <signal.h> ++#include <orb/orbit.h> ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include "echo.h" ++#include "glib.h" ++#include "korbit.h" ++ ++Echo echo_client = CORBA_OBJECT_NIL; ++ ++static CORBA_Object ++do_echoString(PortableServer_Servant servant, ++ CORBA_char *astring, ++ CORBA_long *outnum, ++ CORBA_Environment *ev); ++ ++PortableServer_ServantBase__epv base_epv = { ++ NULL, ++ NULL, ++ NULL ++}; ++POA_Echo__epv echo_epv = { NULL, do_echoString }; ++POA_Echo__vepv poa_echo_vepv = { &base_epv, &echo_epv }; ++POA_Echo poa_echo_servant = { NULL, &poa_echo_vepv }; ++ ++PortableServer_ObjectId objid = {0, sizeof("myEchoString"), "myEchoString"}; ++PortableServer_POA poa; ++CORBA_Environment *ev; ++ ++#ifdef __KERNEL__ ++int __init corba_echo_init(void) ++#else ++int main(int argc, char *argv[]) ++#endif ++{ ++#ifdef __KERNEL__ ++ int argc = 1; char *argv[] = { "server", 0 }; ++#endif ++ CORBA_ORB orb; ++ ev = g_new0(CORBA_Environment, 1); ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ if (!orb) { ++ printf("Error getting ORB!\n"); ++ return 1; ++ } ++ ++ poa = (PortableServer_POA) ++ CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev); ++ if (!poa) { ++ printf("Error getting POA!\n"); ++ return 1; ++ } ++ ++ PortableServer_POAManager_activate( ++ PortableServer_POA__get_the_POAManager(poa, ev), ev); ++ ++ ++ POA_Echo__init(&poa_echo_servant, ev); ++ PortableServer_POA_activate_object_with_id(poa, ++ &objid, &poa_echo_servant, ev); ++ ++ echo_client = PortableServer_POA_servant_to_reference(poa, ++ &poa_echo_servant, ++ ev); ++ if (!echo_client) { ++ printf("Cannot get objref\n"); ++ return 1; ++ } ++ ++ korbit_register_ior("echo-server", echo_client, orb, ev); ++ ++ CORBA_ORB_run(orb, ev); ++ return 0; ++} ++ ++#ifdef __KERNEL__ ++void corba_echo_exit(void) { ++ PortableServer_POA_deactivate_object(poa, &objid, ev); ++ remove_proc_entry("corba/echo-server", 0); ++} ++ ++module_init(corba_echo_init) ++module_exit(corba_echo_exit) ++#endif ++ ++static CORBA_Object ++do_echoString(PortableServer_Servant servant, ++ CORBA_char *astring, ++ CORBA_long *outnum, ++ CORBA_Environment *ev) ++{ ++ *outnum = 12345678; ++ ++#if 1 ++ g_message("[server] %s -> %d", astring, *outnum); ++#endif ++ ++ return CORBA_Object_duplicate(echo_client, ev); ++} +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c +--- linux-2.4.1/net/korbit/modules/Echo/server/echo-skels.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-skels.c Thu Feb 1 16:36:57 2001 +@@ -0,0 +1,115 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "echo.h" ++ ++void ++_ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ Echo(*_impl_echoString) (PortableServer_Servant ++ _servant, ++ const CORBA_char * ++ astring, ++ CORBA_long * anum, ++ CORBA_Environment * ev)) ++{ ++ Echo _ORBIT_retval; ++ CORBA_char *astring; ++ CORBA_long anum; ++ ++ { /* demarshalling */ ++ guchar *_ORBIT_curptr; ++ register CORBA_unsigned_long _ORBIT_tmpvar_2; ++ CORBA_unsigned_long _ORBIT_tmpvar_3; ++ ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & (_ORBIT_tmpvar_3))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr)); ++ _ORBIT_curptr += 4; ++ astring = (void *) _ORBIT_curptr; ++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3; ++ } else { ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ _ORBIT_tmpvar_3 = *((CORBA_unsigned_long *) _ORBIT_curptr); ++ _ORBIT_curptr += 4; ++ astring = (void *) _ORBIT_curptr; ++ _ORBIT_curptr += sizeof(astring[_ORBIT_tmpvar_2]) * _ORBIT_tmpvar_3; ++ } ++ } ++ _ORBIT_retval = _impl_echoString(_ORBIT_servant, astring, &(anum), ev); ++ { /* marshalling */ ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ ++ _ORBIT_send_buffer = ++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection, NULL, ++ _ORBIT_recv_buffer->message.u.request. ++ request_id, ev->_major); ++ if (_ORBIT_send_buffer) { ++ if (ev->_major == CORBA_NO_EXCEPTION) { ++ ORBit_marshal_object(_ORBIT_send_buffer, _ORBIT_retval); ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), &(anum), ++ sizeof(anum)); ++ } else ++ ORBit_send_system_exception(_ORBIT_send_buffer, ev); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ } ++ if (ev->_major == CORBA_NO_EXCEPTION) ++ CORBA_Object_release(_ORBIT_retval, ev); ++ } ++} ++static ORBitSkeleton ++get_skel_Echo(POA_Echo * servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, gpointer * impl) ++{ ++ gchar *opname = _ORBIT_recv_buffer->message.u.request.operation; ++ ++ switch (opname[0]) { ++ case 'e': ++ if (strcmp((opname + 1), "choString")) ++ break; ++ *impl = (gpointer) servant->vepv->Echo_epv->echoString; ++ return (ORBitSkeleton) _ORBIT_skel_Echo_echoString; ++ break; ++ default: ++ break; ++ } ++ return NULL; ++} ++ ++static void ++init_local_objref_Echo(CORBA_Object obj, POA_Echo * servant) ++{ ++ obj->vepv[Echo__classid] = servant->vepv->Echo_epv; ++} ++ ++void ++POA_Echo__init(PortableServer_Servant servant, CORBA_Environment * env) ++{ ++ static const PortableServer_ClassInfo class_info = ++ { (ORBit_impl_finder) & get_skel_Echo, "IDL:Echo:1.0", ++ (ORBit_local_objref_init) & init_local_objref_Echo }; ++ ++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), ++ env); ++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *) servant)->_private)-> ++ class_info = (PortableServer_ClassInfo *) & class_info; ++ if (!Echo__classid) ++ Echo__classid = ORBit_register_class(&class_info); ++} ++ ++void ++POA_Echo__fini(PortableServer_Servant servant, CORBA_Environment * env) ++{ ++ PortableServer_ServantBase__fini(servant, env); ++} +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c +--- linux-2.4.1/net/korbit/modules/Echo/server/echo-stubs.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo-stubs.c Thu Feb 1 16:36:57 2001 +@@ -0,0 +1,134 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <string.h> ++#include "echo.h" ++ ++Echo ++Echo_echoString(Echo _obj, const CORBA_char * astring, CORBA_long * anum, ++ CORBA_Environment * ev) ++{ ++ register GIOP_unsigned_long _ORBIT_request_id, ++ _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ Echo _ORBIT_retval; ++ ++ if (_obj->servant && _obj->vepv && Echo__classid) { ++ _ORBIT_retval = ++ ((POA_Echo__epv *) _obj->vepv[Echo__classid])->echoString(_obj-> ++ servant, ++ astring, ++ anum, ev); ++ return _ORBIT_retval; ++ } ++ _cnx = ORBit_object_get_connection(_obj); ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ _ORBIT_request_id = GPOINTER_TO_UINT(alloca(0)); ++ { /* marshalling */ ++ static const struct ++ { ++ CORBA_unsigned_long len; ++ char opname[11]; ++ } ++ _ORBIT_operation_name_data = ++ { ++ 11, "echoString"}; ++ static const struct iovec _ORBIT_operation_vec = ++ { (gpointer) & _ORBIT_operation_name_data, 15 }; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, ++ CORBA_TRUE, ++ &(_obj->active_profile->object_key_vec), ++ &_ORBIT_operation_vec, ++ &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(astring) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), 4); ++ { ++ guchar *_ORBIT_t; ++ ++ _ORBIT_t = alloca(sizeof(_ORBIT_tmpvar_1)); ++ memcpy(_ORBIT_t, &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER ++ (_ORBIT_send_buffer), (_ORBIT_t), ++ sizeof(_ORBIT_tmpvar_1)); ++ } ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), ++ (astring), ++ sizeof(astring[_ORBIT_tmpvar_0]) * ++ _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ ++ _ORBIT_recv_buffer = ++ giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != ++ GIOP_NO_EXCEPTION) goto _ORBIT_msg_exception; ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ ++ (*((guint32 *) & ((*anum)))) = ++ GUINT32_SWAP_LE_BE(*((guint32 *) _ORBIT_curptr));} else { ++ GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur = _ORBIT_curptr; ++ _ORBIT_retval = ++ ORBit_demarshal_object(_ORBIT_recv_buffer, ++ GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)-> ++ connection->orb_data); ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_curptr = ALIGN_ADDRESS(_ORBIT_curptr, 4); ++ (*anum) = *((CORBA_long *) _ORBIT_curptr); ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, ++ _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == ++ GIOP_LOCATION_FORWARD) { ++ if (_obj->forward_locations != NULL) ++ ORBit_delete_profiles(_obj->forward_locations); ++ _obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(_obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, _obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++} +diff -urN linux-2.4.1/net/korbit/modules/Echo/server/echo.h linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h +--- linux-2.4.1/net/korbit/modules/Echo/server/echo.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Echo/server/echo.h Thu Feb 1 16:36:57 2001 +@@ -0,0 +1,77 @@ ++/* ++ * This file was generated by orbit-idl - DO NOT EDIT! ++ */ ++ ++#include <glib.h> ++#define ORBIT_IDL_SERIAL 9 ++#include <orb/orbit.h> ++ ++#ifndef echo_H ++#define echo_H 1 ++#ifdef __cplusplus ++extern "C" ++{ ++#endif /* __cplusplus */ ++ ++/** typedefs **/ ++#if !defined(ORBIT_DECL_Echo) && !defined(_Echo_defined) ++#define ORBIT_DECL_Echo 1 ++#define _Echo_defined 1 ++#define Echo__free CORBA_Object__free ++ typedef CORBA_Object Echo; ++ extern CORBA_unsigned_long Echo__classid; ++#if !defined(TC_IMPL_TC_Echo_0) ++#define TC_IMPL_TC_Echo_0 'e' ++#define TC_IMPL_TC_Echo_1 'c' ++#define TC_IMPL_TC_Echo_2 'h' ++#define TC_IMPL_TC_Echo_3 'o' ++ extern const struct CORBA_TypeCode_struct TC_Echo_struct; ++#define TC_Echo ((CORBA_TypeCode)&TC_Echo_struct) ++#endif ++#endif ++ ++/** POA structures **/ ++ typedef struct ++ { ++ void *_private; ++ ++ Echo(*echoString) (PortableServer_Servant _servant, ++ const CORBA_char * astring, CORBA_long * anum, ++ CORBA_Environment * ev); ++ } ++ POA_Echo__epv; ++ typedef struct ++ { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_Echo__epv *Echo_epv; ++ } ++ POA_Echo__vepv; ++ typedef struct ++ { ++ void *_private; ++ POA_Echo__vepv *vepv; ++ } ++ POA_Echo; ++ extern void POA_Echo__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ extern void POA_Echo__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ ++/** prototypes **/ ++ Echo Echo_echoString(Echo _obj, const CORBA_char * astring, ++ CORBA_long * anum, CORBA_Environment * ev); ++ ++ void _ORBIT_skel_Echo_echoString(POA_Echo * _ORBIT_servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment * ev, ++ Echo(*_impl_echoString) ++ (PortableServer_Servant _servant, ++ const CORBA_char * astring, ++ CORBA_long * anum, ++ CORBA_Environment * ev)); ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif ++#undef ORBIT_IDL_SERIAL +diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries +--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,4 @@ ++/FileServer.idl/1.3/Thu Feb 1 09:47:07 2001// ++/Makefile/1.2/Thu Feb 1 09:47:07 2001// ++/README/1.1/Thu Feb 1 09:47:07 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Entries.Log Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,4 @@ ++A D/client//// ++A D/server//// ++A D/server-user//// ++A D/wrapper//// +diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository +--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Repository Thu Feb 1 11:47:07 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/FileServer +diff -urN linux-2.4.1/net/korbit/modules/FileServer/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root +--- linux-2.4.1/net/korbit/modules/FileServer/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/CVS/Root Thu Feb 1 11:47:07 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl +--- linux-2.4.1/net/korbit/modules/FileServer/FileServer.idl Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/FileServer.idl Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,158 @@ ++// ----------------------------------------------------------------------------- ++// FileServer.idl ++// ----------------------------------------------------------------------------- ++// ++// This file is used to define the Kernel CORBA API for accessing the filesystem ++// on a machine. This defines mappings both to access the files in the kernel ++// and to implement a filesystem for the kernel. This should probably be split ++// into two files eventually. ++// ++// Currently unimplemented: KernelAccessAPI::FileSystem::ReadDirectory ++// KernelAccessAPI::FileSystem::Select ++// KernelImplementationAPI::SuperBlock::getDiskQuotaOps ++// ++// ----------------------------------------------------------------------------- ++ ++ ++// These are the exceptions that may be thrown and what they map to in the ++// Linux kernel. This interface is extended by other interfaces so that the ++// names don't have to be typedef'd into each interface that wants to use these ++// errors. ++// ++interface Errors { ++ exception IsDirectory {}; // EISDIR ++ exception PermissionDenied {}; // EACCES ++ exception FileExists {}; // EEXIST ++ exception FileNotFound {}; // ENOENT ++ exception IsNotDirectory {}; // ENOTDIR ++ exception ReadOnlyFile {}; // EROFS, ETXTBSY ++ exception RecursiveSymlink {}; // ELOOP ++ exception IsBusy {}; // EBUSY ++ exception OtherError{}; // Misc other ones... ++}; ++ ++ ++// ----------------------------------------------------------------------------- ++// KernelAccessAPI Module - Allow user level programs to call into the kernel ++// ----------------------------------------------------------------------------- ++ ++module FileServer { ++ struct FileStatus { // Corba equilivant of struct stat ++ long DeviceNum; // st_dev ++ long InodeNum; // st_ino ++ short Mode; // st_mode ++ short NumLinks; // st_nlink ++ long UserID; // st_uid ++ long GroupID; // st_gid ++ long DeviceType; // st_rdev ++ unsigned long Size; // st_size ++ unsigned long BlockSize; // st_blksize ++ unsigned long NumBlocks; // st_blocks; ++ unsigned long AccessTime; // st_blocks; ++ unsigned long ModifiedTime; // st_blocks; ++ unsigned long ChangeTime; // st_blocks; ++ }; ++ ++ typedef sequence<octet> buffer; ++ ++ // --------------------------------------------------------------------------- ++ // FileSystem Interface - Access to filesystem and File object factory ++ // --------------------------------------------------------------------------- ++ ++ interface File : Errors { ++ void Read(in long count, out buffer buf) ++ raises (IsDirectory, OtherError); ++ void Write(in buffer buf) ++ raises (OtherError); ++ void Close(); ++ ++ long FileControl(in long command) raises (OtherError); ++ ++ FileStatus GetStatus() raises (OtherError); ++ ++ void ChangeDirectoryTo() // This implements fchdir... ++ raises (IsNotDirectory, PermissionDenied, OtherError); ++ ++ enum SeekDirection { FromStart, FromCurrent, FromEnd }; ++ long Seek(in long Offset, in SeekDirection Direction) raises (OtherError); ++ ++ File Duplicate() raises (OtherError); ++ }; ++ ++ ++ ++ // --------------------------------------------------------------------------- ++ // FileSystem Interface - Access to filesystem and File object factory ++ // --------------------------------------------------------------------------- ++ ++ interface FileSystem : Errors { ++ ++ // ------------------------------------------------------------------------- ++ // File Manipulation Routines ++ // ------------------------------------------------------------------------- ++ ++ File Open(in string Filename, in long openFlags, in short mode) ++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound, ++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError); ++ ++ File Create(in string Filename, in short mode) ++ raises (FileExists, IsDirectory, PermissionDenied, FileNotFound, ++ IsNotDirectory, ReadOnlyFile, RecursiveSymlink, OtherError); ++ ++ void Link(in string FromPath, in string ToPath) ++ raises (PermissionDenied, IsNotDirectory, RecursiveSymlink, FileExists); ++ ++ void Unlink(in string Filename) ++ raises (PermissionDenied, FileNotFound, IsNotDirectory, IsDirectory); ++ ++ void Rename(in string OldName, in string NewName) ++ raises (IsDirectory, FileExists, IsBusy, IsNotDirectory, PermissionDenied, ++ RecursiveSymlink); ++ ++ void ReadLink(in string Linkname, out string LinkValue) ++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, OtherError); ++ ++ ++ FileStatus GetStatus(in string Filename) ++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory, ++ OtherError); ++ ++ FileStatus GetLinkStatus(in string Filename) ++ raises (FileNotFound, PermissionDenied, RecursiveSymlink, IsNotDirectory, ++ OtherError); ++ ++ ++ // ------------------------------------------------------------------------- ++ // Directory Manipulation Routines ++ // ------------------------------------------------------------------------- ++ ++ void MakeDirectory(in string PathName, in short mode) ++ raises (FileExists, PermissionDenied, FileNotFound, IsNotDirectory, ++ ReadOnlyFile, RecursiveSymlink, OtherError); ++ ++ void RemoveDirectory(in string PathName) ++ raises (PermissionDenied, FileNotFound, IsNotDirectory); ++ ++ // ChangeDirectory returns CWD so that you can implement getcwd as ++ // { return ChangeDirectory("."); } ++ string ChangeDirectory(in string PathName) ++ raises (IsNotDirectory, PermissionDenied, FileNotFound, RecursiveSymlink); ++ ++ ++ // ------------------------------------------------------------------------- ++ // Special Purpose Routines... ++ // ------------------------------------------------------------------------- ++ ++ void MakeNode(in string FileName, in short Mode, in long DeviceNum) ++ raises (PermissionDenied, FileExists, FileNotFound, IsNotDirectory, ++ RecursiveSymlink); ++ ++ void Mount(in string DeviceFile, in string Location, in string FSType, ++ in long Flags) ++ raises (PermissionDenied, FileNotFound, IsBusy, IsNotDirectory); ++ ++ void Unmount(in string Filename) ++ raises (PermissionDenied, FileNotFound, IsBusy); ++ }; ++ ++}; +diff -urN linux-2.4.1/net/korbit/modules/FileServer/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile +--- linux-2.4.1/net/korbit/modules/FileServer/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/Makefile Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,11 @@ ++# ++# Makefile for KORBit/modules/CorbaFS ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_FILESERVER) := server ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/FileServer/README linux-2.4.1-korbit/net/korbit/modules/FileServer/README +--- linux-2.4.1/net/korbit/modules/FileServer/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/README Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,8 @@ ++This interface lets you export file related syscalls through CORBA. This is ++genuinely useful, however, when you use the 'wrapper' library, that can be ++LD_PRELOADED before you run your application. This allows you to forward ++filesystem calls through CORBA without having to modify your application. ++ ++Being able to forward filesystem calls though CORBA, of course, means that ++you can attach to any remote machine you want. :) ++ +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries +--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Entries Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,4 @@ ++/FileServer-client.cpp/1.1/Thu Feb 1 09:47:07 2001// ++/Makefile/1.1/Thu Feb 1 09:47:07 2001// ++/README/1.1/Thu Feb 1 09:47:07 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository +--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Repository Thu Feb 1 11:47:07 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/FileServer/client +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root +--- linux-2.4.1/net/korbit/modules/FileServer/client/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/CVS/Root Thu Feb 1 11:47:07 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp +--- linux-2.4.1/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/FileServer-client.cpp Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,78 @@ ++#include <OB/CORBA.h> ++#include <OB/Util.h> ++#include <OB/CosNaming.h> ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++#include "FileServer.h" ++ ++int main(int argc, char* argv[]) ++{ ++ if (argc < 3) ++ { ++ cout << "Usage : " << argv[0] << " ior filename" << endl; ++ exit(1); ++ } ++ ++ cout << "FileServer client initializing" << endl; ++ ++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv); ++ cout << "ORB initialized" << endl; ++ ++ try ++ { ++ CORBA_Object_var obj = orb->string_to_object( argv[1] ); ++ assert(!CORBA_is_nil(obj)); ++ cout << "got object... " << orb->object_to_string(obj) << endl; ++ ++ FileServer_FileSystem_var fs = FileServer_FileSystem::_narrow(obj); ++ assert(!CORBA_is_nil(fs)); ++ cout << "it's a FileServer!" << endl; ++ ++ obj = fs->Open(argv[2], O_RDONLY, 0); ++ assert(!CORBA_is_nil(obj)); ++ cout << "got object... " << orb->object_to_string(obj) << endl; ++ ++ FileServer_File_var file = FileServer_File::_narrow(obj); ++ assert(!CORBA_is_nil(file)); ++ cout << "it's a FileServer_File!" << endl; ++ ++ FileServer_buffer *buf = new FileServer_buffer; ++ cout << "reading 1000 bytes" << endl; ++ file->Read(1000, buf); ++ ++ cout << "got " << buf->length() << " bytes" << endl; ++ cout << buf->data() << endl; ++ ++ file->Close(); ++ ++ delete buf; ++ } ++ catch (const CORBA_SystemException& ex) { ++ OBPrintException(ex); ++ return 1; ++ } ++ catch (const Errors::FileNotFound& ex) { ++ cout << "ERROR : File not found" << endl; ++ return 1; ++ } ++ catch (const Errors::PermissionDenied& ex) { ++ cout << "ERROR : Permission denied" << endl; ++ return 1; ++ } ++ catch (const Errors::IsDirectory& ex) { ++ cout << "ERROR : Is directory" << endl; ++ return 1; ++ } ++ catch (const Errors::OtherError& ex) { ++ cout << "ERROR : Other error" << endl; ++ return 1; ++ } ++ catch (const CORBA_UserException& ex) ++ { ++ cout << "ERROR : Uncaught exception" << endl; ++ return 1; ++ } ++} +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile +--- linux-2.4.1/net/korbit/modules/FileServer/client/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/Makefile Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,32 @@ ++CC = CC -mt -pta ++OBDIR = /home/class/cs423/local ++IDL = $(OBDIR)/bin/idl ++CPPFLAGS = -I. -I$(OBDIR)/include ++LDFLAGS = -L$(OBDIR)/lib ++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4 ++ ++all: FileServer-client ++ ++FileServer-client: FileServer.o FileServer-client.o ++ $(CC) $(LDFLAGS) -o FileServer-client FileServer-client.o FileServer.o $(LIBS) ++ ++nameserv: ++ nameserv -i -OAport 10000 ++ ++FileServer.h FileServer.cpp: ../FileServer.idl ++ rm -f FileServer.cpp FileServer.h ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ $(IDL) ../FileServer.idl ++ ++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp ++ ++%.o: %.cpp ++ $(CC) $(CPPFLAGS) -c $< ++ ++clean: ++ rm -f FileServer-client *.o *~ ++ ++realclean: clean ++ rm -f FileServer.h FileServer.cpp ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ rm -rf SunWS_cache +diff -urN linux-2.4.1/net/korbit/modules/FileServer/client/README linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README +--- linux-2.4.1/net/korbit/modules/FileServer/client/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/client/README Thu Feb 1 11:47:07 2001 +@@ -0,0 +1,4 @@ ++Very minimal test of the FileServer capability. ++ ++ORB: Orbacus ++ +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries +--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Entries Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,6 @@ ++/FileServer-server.c/1.2/Thu Feb 1 09:47:08 2001// ++/FileServer-skelimpl.c/1.8/Thu Feb 1 09:47:08 2001// ++/Makefile/1.3/Thu Feb 1 09:47:08 2001// ++/Makefile.user/1.4/Thu Feb 1 09:47:08 2001// ++/README/1.1/Thu Feb 1 09:47:08 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository +--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Repository Thu Feb 1 11:47:08 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root +--- linux-2.4.1/net/korbit/modules/FileServer/server/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/CVS/Root Thu Feb 1 11:47:08 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c +--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-server.c Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,57 @@ ++#include <stdio.h> ++#include "FileServer-skelimpl.c" ++#include "korbit.h" ++ ++CORBA_ORB orb; ++PortableServer_POA poa; ++CORBA_Environment *ev; ++PortableServer_ObjectId *objid; ++ ++#ifdef __KERNEL__ ++int __init FileServer_init(void) { ++#else ++int main(int argc, char *argv[]) { ++#endif ++ FileServer_FileSystem fs; ++ impl_POA_FileServer_FileSystem *fs_impl; ++ ++ PortableServer_POAManager pm; ++#ifdef __KERNEL__ ++ int argc = 1; ++ char *argv[] = { "server", 0 }; ++#endif ++ ev = g_new0(CORBA_Environment,1); ++ ++ CORBA_exception_init(ev); ++ ++ orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); ++ poa = (PortableServer_POA) ++ CORBA_ORB_resolve_initial_references(orb, ++ "RootPOA", ++ ev); ++ fs = impl_FileServer_FileSystem__create(poa, ev); ++ ++ pm = PortableServer_POA__get_the_POAManager(poa, ev); ++ PortableServer_POAManager_activate(pm, ev); ++ ++ fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev ); ++ objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev ); ++ ++ korbit_register_ior("FileServer-server", fs, orb, ev); ++ ++ CORBA_ORB_run(orb, ev); ++ ++ return 0; ++} ++ ++#ifdef __KERNEL__ ++void FileServer_exit(void) ++{ ++ PortableServer_POA_deactivate_object(poa, objid, ev); ++ remove_proc_entry("corba/FileServer-server", 0); ++ printf("FileServer_exit()\n"); ++} ++ ++module_init(FileServer_init) ++module_exit(FileServer_exit) ++#endif +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c +--- linux-2.4.1/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/FileServer-skelimpl.c Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,804 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <errno.h> ++ ++#include "FileServer.h" ++ ++static void set_exception(int errno, CORBA_Environment *ev) ++{ ++ switch (errno) ++ { ++ case ENOENT: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_FileNotFound, ++ Errors_FileNotFound__alloc()); ++ break; ++ case EEXIST: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_FileExists, ++ Errors_FileExists__alloc()); ++ break; ++ case EACCES: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_PermissionDenied, ++ Errors_PermissionDenied__alloc()); ++ break; ++ case EISDIR: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_IsDirectory, ++ Errors_IsDirectory__alloc()); ++ break; ++ case ENOTDIR: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_IsNotDirectory, ++ Errors_IsNotDirectory__alloc()); ++ break; ++ case EROFS: ++ case ETXTBSY: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_ReadOnlyFile, ++ Errors_ReadOnlyFile__alloc()); ++ break; ++ case ELOOP: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_RecursiveSymlink, ++ Errors_RecursiveSymlink__alloc()); ++ break; ++ case EBUSY: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_IsBusy, ++ Errors_IsBusy__alloc()); ++ break; ++ default: ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_Errors_OtherError, ++ Errors_OtherError__alloc()); ++ break; ++ } ++} ++ ++ ++/*** App-specific servant structures ***/ ++typedef struct ++{ ++ POA_Errors servant; ++ PortableServer_POA poa; ++ ++} ++impl_POA_Errors; ++ ++typedef struct ++{ ++ POA_FileServer_File servant; ++ PortableServer_POA poa; ++ ++ int fd; ++} ++impl_POA_FileServer_File; ++ ++typedef struct ++{ ++ POA_FileServer_FileSystem servant; ++ PortableServer_POA poa; ++ ++} ++impl_POA_FileServer_FileSystem; ++ ++/*** Implementation stub prototypes ***/ ++static void impl_Errors__destroy(impl_POA_Errors * servant, ++ CORBA_Environment * ev); ++ ++static void impl_FileServer_File__destroy(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev); ++static void ++impl_FileServer_File_Read(impl_POA_FileServer_File * servant, ++ CORBA_long count, ++ FileServer_buffer ** buf, CORBA_Environment * ev); ++ ++static void ++impl_FileServer_File_Write(impl_POA_FileServer_File * servant, ++ FileServer_buffer * buf, CORBA_Environment * ev); ++ ++static void ++impl_FileServer_File_Close(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev); ++ ++static CORBA_long ++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant, ++ CORBA_long command, CORBA_Environment * ev); ++ ++static FileServer_FileStatus ++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev); ++ ++static CORBA_long ++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant, ++ CORBA_long Offset, ++ FileServer_File_SeekDirection Direction, ++ CORBA_Environment * ev); ++ ++static FileServer_File ++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev); ++ ++static void impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem ++ * servant, ++ ++ CORBA_Environment * ev); ++static FileServer_File ++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, CORBA_long openFlags, ++ CORBA_short mode, CORBA_Environment * ev); ++ ++static FileServer_File ++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_short mode, CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * FromPath, ++ CORBA_char * ToPath, CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * OldName, ++ CORBA_char * NewName, ++ ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Linkname, ++ CORBA_char ** LinkValue, ++ CORBA_Environment * ev); ++ ++static FileServer_FileStatus ++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_Environment * ev); ++ ++static FileServer_FileStatus ++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * Filename, ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * PathName, ++ CORBA_short mode, ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * PathName, ++ CORBA_Environment * ev); ++ ++static CORBA_char ++ *impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem ++ * servant, ++ CORBA_char * PathName, ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * FileName, ++ CORBA_short Mode, ++ CORBA_long DeviceNum, ++ ++ CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * DeviceFile, ++ CORBA_char * Location, ++ CORBA_char * FSType, ++ CORBA_long Flags, CORBA_Environment * ev); ++ ++static void ++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ ++ CORBA_Environment * ev); ++ ++/*** epv structures ***/ ++static PortableServer_ServantBase__epv impl_Errors_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_Errors__epv impl_Errors_epv = { ++ NULL, /* _private */ ++ ++}; ++ ++static PortableServer_ServantBase__epv impl_FileServer_File_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_FileServer_File__epv impl_FileServer_File_epv = { ++ NULL, /* _private */ ++ (gpointer) & impl_FileServer_File_Read, ++ ++ (gpointer) & impl_FileServer_File_Write, ++ ++ (gpointer) & impl_FileServer_File_Close, ++ ++ (gpointer) & impl_FileServer_File_FileControl, ++ ++ (gpointer) & impl_FileServer_File_GetStatus, ++ ++ (gpointer) & impl_FileServer_File_ChangeDirectoryTo, ++ ++ (gpointer) & impl_FileServer_File_Seek, ++ ++ (gpointer) & impl_FileServer_File_Duplicate, ++ ++}; ++static POA_Errors__epv impl_FileServer_File_Errors_epv = { ++ NULL, /* _private */ ++}; ++static PortableServer_ServantBase__epv impl_FileServer_FileSystem_base_epv = { ++ NULL, /* _private data */ ++ NULL, /* finalize routine */ ++ NULL, /* default_POA routine */ ++}; ++static POA_FileServer_FileSystem__epv impl_FileServer_FileSystem_epv = { ++ NULL, /* _private */ ++ (gpointer) & impl_FileServer_FileSystem_Open, ++ ++ (gpointer) & impl_FileServer_FileSystem_Create, ++ ++ (gpointer) & impl_FileServer_FileSystem_Link, ++ ++ (gpointer) & impl_FileServer_FileSystem_Unlink, ++ ++ (gpointer) & impl_FileServer_FileSystem_Rename, ++ ++ (gpointer) & impl_FileServer_FileSystem_ReadLink, ++ ++ (gpointer) & impl_FileServer_FileSystem_GetStatus, ++ ++ (gpointer) & impl_FileServer_FileSystem_GetLinkStatus, ++ ++ (gpointer) & impl_FileServer_FileSystem_MakeDirectory, ++ ++ (gpointer) & impl_FileServer_FileSystem_RemoveDirectory, ++ ++ (gpointer) & impl_FileServer_FileSystem_ChangeDirectory, ++ ++ (gpointer) & impl_FileServer_FileSystem_MakeNode, ++ ++ (gpointer) & impl_FileServer_FileSystem_Mount, ++ ++ (gpointer) & impl_FileServer_FileSystem_Unmount, ++ ++}; ++static POA_Errors__epv impl_FileServer_FileSystem_Errors_epv = { ++ NULL, /* _private */ ++}; ++ ++/*** vepv structures ***/ ++static POA_Errors__vepv impl_Errors_vepv = { ++ &impl_Errors_base_epv, ++ &impl_Errors_epv, ++}; ++ ++static POA_FileServer_File__vepv impl_FileServer_File_vepv = { ++ &impl_FileServer_File_base_epv, ++ &impl_FileServer_File_Errors_epv, ++ &impl_FileServer_File_epv, ++}; ++static POA_FileServer_FileSystem__vepv impl_FileServer_FileSystem_vepv = { ++ &impl_FileServer_FileSystem_base_epv, ++ &impl_FileServer_FileSystem_Errors_epv, ++ &impl_FileServer_FileSystem_epv, ++}; ++ ++/*** Stub implementations ***/ ++static Errors ++impl_Errors__create(PortableServer_POA poa, CORBA_Environment * ev) ++{ ++ Errors retval; ++ impl_POA_Errors *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_Errors, 1); ++ newservant->servant.vepv = &impl_Errors_vepv; ++ newservant->poa = poa; ++ POA_Errors__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static void ++impl_Errors__destroy(impl_POA_Errors * servant, CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_Errors__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static FileServer_File ++impl_FileServer_File__create(PortableServer_POA poa, CORBA_Environment * ev) ++{ ++ FileServer_File retval; ++ impl_POA_FileServer_File *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_FileServer_File, 1); ++ newservant->servant.vepv = &impl_FileServer_File_vepv; ++ newservant->poa = poa; ++ newservant->fd = -1; ++ ++ POA_FileServer_File__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static void ++impl_FileServer_File__destroy(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_FileServer_File__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static void ++impl_FileServer_File_Read(impl_POA_FileServer_File * servant, ++ CORBA_long count, ++ FileServer_buffer ** buf, CORBA_Environment * ev) ++{ ++ size_t num_read; ++ ++ *buf = FileServer_buffer__alloc(); ++ (*buf)->_maximum = count; ++ (*buf)->_buffer = CORBA_octet_allocbuf(count); ++ (*buf)->_length = 0; ++ ++ printf("File->Read(%d, char *buf)\n", count); ++ ++ if (servant->fd == -1) /* Trying to read from a closed file */ ++ { ++ printf("File->Read ERROR : fd == -1\n"); ++ set_exception(EBADF, ev); ++ return; ++ } ++ ++ num_read = read(servant->fd, (*buf)->_buffer, count); ++ if (num_read == -1) ++ { ++ printf("File->Read ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ return; ++ } ++ ++ (*buf)->_length = num_read; ++} ++ ++static void ++impl_FileServer_File_Write(impl_POA_FileServer_File * servant, ++ FileServer_buffer * buf, CORBA_Environment * ev) ++{ ++ printf("UNIMP: FileServer::File::Write called and unimplemented\n"); ++} ++ ++static void ++impl_FileServer_File_Close(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev) ++{ ++ printf("File->Close()\n"); ++ ++ if (servant->fd == -1) /* This should never happen !?! */ ++ { ++ printf("File->Close ERROR : fd == -1\n"); ++ set_exception(EBADF, ev); ++ return; ++ } ++ ++ close(servant->fd); ++ servant->fd = 0; ++ impl_FileServer_File__destroy(servant, ev); ++} ++ ++static CORBA_long ++impl_FileServer_File_FileControl(impl_POA_FileServer_File * servant, ++ CORBA_long command, CORBA_Environment * ev) ++{ ++ CORBA_long retval; ++ ++ if (servant->fd == -1) ++ { ++ printf("File->FileControl ERROR : fd == -1\n"); ++ set_exception(EBADF, ev); ++ return -1; ++ } ++ ++ retval = fcntl(servant->fd, command, 0); /* FIXME arg? */ ++ if (retval == -1) ++ { ++ printf("File->FileControl ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ } ++ ++ return retval; ++} ++ ++ ++FileServer_FileStatus ++stat2FileStatus(struct stat buf) ++{ ++ FileServer_FileStatus retval; ++ ++ retval.DeviceNum = buf.st_dev; ++ retval.InodeNum = buf.st_ino; ++ retval.Mode = buf.st_mode; ++ retval.NumLinks = buf.st_nlink; ++ retval.UserID = buf.st_uid; ++ retval.GroupID = buf.st_gid; ++ retval.DeviceType = buf.st_rdev; ++ retval.Size = buf.st_size; ++ retval.BlockSize = buf.st_blksize; ++ retval.NumBlocks = buf.st_blocks; ++ retval.AccessTime = buf.st_atime; ++ retval.ModifiedTime = buf.st_mtime; ++ retval.ChangeTime = buf.st_ctime; ++ ++ return retval; ++} ++ ++ ++static FileServer_FileStatus ++impl_FileServer_File_GetStatus(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev) ++{ ++ FileServer_FileStatus retval; ++ ++ struct stat buf; ++ int res; ++ ++ if (servant->fd == -1) ++ { ++ printf("File->GetStatus ERROR : fd == -1\n"); ++ set_exception(EBADF, ev); ++ return retval; ++ } ++ ++ res = fstat(servant->fd, &buf); ++ if (res == -1) ++ { ++ printf("File->GetStatus ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ return retval; ++ } ++ ++ retval = stat2FileStatus(buf); ++ ++ return retval; ++} ++ ++static void ++impl_FileServer_File_ChangeDirectoryTo(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_File_ChangeDirectoryTo\n"); ++} ++ ++static CORBA_long ++impl_FileServer_File_Seek(impl_POA_FileServer_File * servant, ++ CORBA_long Offset, ++ FileServer_File_SeekDirection Direction, ++ CORBA_Environment * ev) ++{ ++ CORBA_long retval = -1; ++ int whence; ++ ++ if (servant->fd == -1) ++ { ++ printf("File->Seek ERROR : fd == -1\n"); ++ set_exception(EBADF, ev); ++ return retval; ++ } ++ ++ switch (Direction) ++ { ++ case FileServer_File_FromStart : ++ whence = SEEK_SET; ++ break; ++ case FileServer_File_FromCurrent : ++ whence = SEEK_CUR; ++ break; ++ case FileServer_File_FromEnd : ++ whence = SEEK_END; ++ break; ++ default : ++ set_exception(EINVAL, ev); ++ return retval; ++ } ++ ++ retval = lseek(servant->fd, Offset, whence); ++ if (retval == -1) ++ { ++ printf("File->Seek ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ } ++ ++ return retval; ++} ++ ++static FileServer_File ++impl_FileServer_File_Duplicate(impl_POA_FileServer_File * servant, ++ CORBA_Environment * ev) ++{ ++ FileServer_File retval; ++ printf("UNIMP: impl_FileServer_File_Duplicate\n"); ++ return retval; ++} ++ ++static FileServer_FileSystem ++impl_FileServer_FileSystem__create(PortableServer_POA poa, ++ CORBA_Environment * ev) ++{ ++ FileServer_FileSystem retval; ++ impl_POA_FileServer_FileSystem *newservant; ++ PortableServer_ObjectId *objid; ++ ++ newservant = g_new0(impl_POA_FileServer_FileSystem, 1); ++ newservant->servant.vepv = &impl_FileServer_FileSystem_vepv; ++ newservant->poa = poa; ++ POA_FileServer_FileSystem__init((PortableServer_Servant) newservant, ev); ++ objid = PortableServer_POA_activate_object(poa, newservant, ev); ++ CORBA_free(objid); ++ retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); ++ ++ return retval; ++} ++ ++static void ++impl_FileServer_FileSystem__destroy(impl_POA_FileServer_FileSystem * servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ObjectId *objid; ++ ++ objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); ++ PortableServer_POA_deactivate_object(servant->poa, objid, ev); ++ CORBA_free(objid); ++ ++ POA_FileServer_FileSystem__fini((PortableServer_Servant) servant, ev); ++ g_free(servant); ++} ++ ++static FileServer_File ++impl_FileServer_FileSystem_Open(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_long openFlags, ++ CORBA_short mode, CORBA_Environment * ev) ++{ ++ FileServer_File retval = CORBA_OBJECT_NIL; ++ ++ impl_POA_FileServer_File *file; ++ ++ printf("FileSystem->Open(%s,%x)\n", Filename, openFlags); ++ ++ retval = impl_FileServer_File__create(servant->poa, ev); ++ ++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev ); ++ file->fd = open(Filename, openFlags, mode); ++ ++ if (file->fd == -1) { ++ printf("FileSystem->Open ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ } ++ ++ return retval; ++} ++ ++static FileServer_File ++impl_FileServer_FileSystem_Create(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_short mode, CORBA_Environment * ev) ++{ ++ FileServer_File retval = CORBA_OBJECT_NIL; ++ ++ impl_POA_FileServer_File *file; ++ ++ printf("FileSystem->Create(%s,%x)\n", Filename, mode); ++ ++ retval = impl_FileServer_File__create(servant->poa, ev); ++ ++ file = PortableServer_POA_reference_to_servant( servant->poa, retval, ev ); ++ file->fd = creat(Filename, mode); ++ ++ if (file->fd == -1) { ++ printf("FileSystem->Create ERROR : %d\n", errno); ++ set_exception(errno, ev); ++ } ++ ++ return retval; ++} ++ ++static void ++impl_FileServer_FileSystem_Link(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * FromPath, ++ CORBA_char * ToPath, CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_Link\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_Unlink(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_Unlink\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_Rename(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * OldName, ++ CORBA_char * NewName, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_Rename\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_ReadLink(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Linkname, ++ CORBA_char ** LinkValue, ++ CORBA_Environment * ev) ++{ ++ char tmp[PATH_MAX + 1]; ++ int res, len; ++ ++ printf("FileSystem->ReadLink(%s, value)\n", Linkname); ++ ++ res = readlink(Linkname, tmp, PATH_MAX); ++ if (res == -1) ++ { ++ set_exception(errno, ev); ++ return; ++ } ++ ++ len = strlen(tmp); ++ *LinkValue = (char *)malloc(len * sizeof(char)); ++ memcpy(*LinkValue, tmp, len); ++ (*LinkValue)[len] = '\0'; ++} ++ ++static FileServer_FileStatus ++impl_FileServer_FileSystem_GetStatus(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_Environment * ev) ++{ ++ FileServer_FileStatus retval; ++ struct stat buf; ++ int res; ++ ++ printf("FileSystem->GetStatus(%s)\n", Filename); ++ ++ res = stat(Filename, &buf); ++ ++ if (res == -1) ++ { ++ printf("FileSystem->GetStatus(%s)\n", Filename); ++ set_exception(errno, ev); ++ return retval; ++ } ++ ++ retval = stat2FileStatus(buf); ++ ++ return retval; ++} ++ ++static FileServer_FileStatus ++impl_FileServer_FileSystem_GetLinkStatus(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * Filename, ++ CORBA_Environment * ev) ++{ ++ FileServer_FileStatus retval; ++ struct stat buf; ++ int res; ++ ++ printf("FileSystem->GetLinkStatus(%s)\n", Filename); ++ ++ res = lstat(Filename, &buf); ++ ++ if (res == -1) ++ { ++ printf("FileSystem->GetLinkStatus(%s)\n", Filename); ++ set_exception(errno, ev); ++ return retval; ++ } ++ ++ retval = stat2FileStatus(buf); ++ ++ return retval; ++} ++ ++static void ++impl_FileServer_FileSystem_MakeDirectory(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * PathName, ++ CORBA_short mode, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_MakeDirectory\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_RemoveDirectory(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * PathName, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_RemoveDirectory\n"); ++} ++ ++static CORBA_char * ++impl_FileServer_FileSystem_ChangeDirectory(impl_POA_FileServer_FileSystem * ++ servant, CORBA_char * PathName, ++ CORBA_Environment * ev) ++{ ++ CORBA_char *retval; ++ printf("UNIMP: impl_FileServer_FileSystem_ChangeDirectory\n"); ++ return retval; ++} ++ ++static void ++impl_FileServer_FileSystem_MakeNode(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * FileName, ++ CORBA_short Mode, ++ CORBA_long DeviceNum, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_MakeNode\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_Mount(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * DeviceFile, ++ CORBA_char * Location, ++ CORBA_char * FSType, ++ CORBA_long Flags, CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_Mount: ARE YOU CRAZY!?!?\n"); ++} ++ ++static void ++impl_FileServer_FileSystem_Unmount(impl_POA_FileServer_FileSystem * servant, ++ CORBA_char * Filename, ++ CORBA_Environment * ev) ++{ ++ printf("UNIMP: impl_FileServer_FileSystem_Unmount: Ha ha ha funny guy!\n"); ++} +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile +--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,20 @@ ++# ++# Makefile for KORBit / FileServer ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := corba-fileserver-server.o ++ ++obj-y := FileServer-common.o FileServer-skels.o FileServer-server.o ++obj-m := $(O_TARGET) ++ ++include ../../Makefile.module ++ ++FileServer-server.c: FileServer.h FileServer-common.c FileServer-skels.c FileServer-skelimpl.c ++ ++FileServer.h FileServer-skels.c FileServer-common.c: ../FileServer.idl ++ $(ORBIT_IDL) ../FileServer.idl +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user +--- linux-2.4.1/net/korbit/modules/FileServer/server/Makefile.user Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/Makefile.user Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,32 @@ ++# ++# Makefile for KORBit ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++PROJECT = FileServer ++ ++CFLAGS = -Wall `orbit-config --cflags server` -I../../.. ++LDFLAGS = `orbit-config --libs server` ++OBJS = $(PROJECT)-common.o $(PROJECT)-skels.o $(PROJECT)-server.o ++ORBIT-IDL = orbit-idl ++ ++$(PROJECT)-server: $(OBJS) ++ gcc -o $(PROJECT)-server $(OBJS) $(LDFLAGS) ++ ++$(PROJECT)-server.c: $(PROJECT).h $(PROJECT)-skelimpl.c ++ ++$(PROJECT).h $(PROJECT)-common.c $(PROJECT)-skels.c $(PROJECT)-skelimpl.c: ../$(PROJECT).idl ++ $(ORBIT-IDL) --nostubs ../$(PROJECT).idl ++ ++clean: ++ rm -f $(OBJS) $(PROJECT)-server ++ ++realclean: clean ++ rm -f $(PROJECT).h ++ rm -f $(PROJECT)-common.c ++ rm -f $(PROJECT)-skels.c ++ rm -f *~ +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README +--- linux-2.4.1/net/korbit/modules/FileServer/server/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server/README Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,4 @@ ++Kernel side implementation of the file server functionality. ++ ++ORB: kORBit ++Status: Mostly unimplemented. +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Entries Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,4 @@ ++/FileServer-server.c/1.1/Thu Feb 1 09:47:08 2001// ++/Makefile/1.1/Thu Feb 1 09:47:08 2001// ++/README/1.1/Thu Feb 1 09:47:08 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Repository Thu Feb 1 11:47:08 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/FileServer/server-user +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/CVS/Root Thu Feb 1 11:47:08 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/FileServer-server.c Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,234 @@ ++#include <OB/CORBA.h> ++#include <OB/Util.h> ++#include <OB/CosNaming.h> ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <errno.h> ++ ++#include "FileServer_skel.h" ++ ++static void ThrowErr() { ++ switch (errno) { ++ case 0: return; ++ case EISDIR: ++ throw Errors::IsDirectory(); ++ case EPERM: ++ throw Errors::PermissionDenied(); ++ case EEXIST: ++ throw Errors::FileExists(); ++ case ENOENT: ++ throw Errors::FileNotFound(); ++ case ENOTDIR: ++ throw Errors::IsNotDirectory(); ++ case EROFS: ++ case ETXTBSY: ++ throw Errors::ReadOnlyFile(); ++ case ELOOP: ++ throw Errors::RecursiveSymlink(); ++ case EBUSY: ++ throw Errors::IsBusy(); ++ default: ++ throw Errors::OtherError(); ++ } ++} ++ ++ ++class FileServer_File_impl : public FileServer_File_skel { ++ int FD; ++ public: ++ FileServer_File_impl(int fd) { FD = fd; } ++ ++ virtual void Read(CORBA_Long count, FileServer_buffer*& buf) { ++ errno = 0; ++ cout << "Read\n"; ++ buf = new FileServer_buffer(); ++ ThrowErr(); ++ } ++ ++ virtual void Write(const FileServer_buffer& buf) { ++ errno = 0; ++ cout << "Write\n"; ++ ThrowErr(); ++ } ++ ++ virtual void Close() { ++ errno = 0; ++ close(FD); ++ cout << "Close()\n"; ++ ThrowErr(); ++ } ++ ++ virtual CORBA_Long FileControl(CORBA_Long command) { ++ errno = 0; ++ cout << "filecontrol\n"; ++ ThrowErr(); ++ return 0; ++ } ++ ++ virtual FileServer_FileStatus GetStatus() { ++ errno = 0; ++ cout << "stat\n"; ++ FileServer_FileStatus Stat; ++ ThrowErr(); ++ return Stat; ++ } ++ ++ virtual void ChangeDirectoryTo() { ++ errno = 0; ++ cout << "ChangeDirectoryTo()\n"; ++ ThrowErr(); ++ } ++ ++ virtual CORBA_Long Seek(CORBA_Long Offset, SeekDirection Direction) { ++ errno = 0; ++ cout << "Seek(" << Offset << ")\n"; ++ ThrowErr(); ++ return -1; ++ } ++ ++ virtual FileServer_File_ptr Duplicate() { ++ errno = 0; ++ cout << "Duplicate!\n"; ++ ThrowErr(); ++ return 0; ++ } ++}; ++ ++ ++class FileServer_impl : public FileServer_FileSystem_skel { ++ public : ++ virtual FileServer_File_ptr Open(const char* Filename, ++ CORBA_Long openFlags, ++ CORBA_Short mode) { ++ errno = 0; ++ int fd = open(Filename, openFlags, mode); ++ if (fd != -1) return new FileServer_File_impl(fd); ++ cout << "open\n"; ++ ThrowErr(); ++ return 0; ++ } ++ ++ virtual FileServer_File_ptr Create(const char* Filename, ++ CORBA_Short mode) { ++ errno = 0; ++ cout << "create\n"; ++ ThrowErr(); ++ return 0; ++ } ++ ++ ++ virtual void Link(const char* FromPath, ++ const char* ToPath) { ++ errno = 0; ++ cout << "link\n"; ++ ThrowErr(); ++ } ++ ++ virtual void Unlink(const char* Filename) { ++ errno = 0; ++ cout << "unlink\n"; ++ ThrowErr(); ++ } ++ ++ virtual void Rename(const char* OldName, ++ const char* NewName) { ++ errno = 0; ++ cout << "rename\n"; ++ ThrowErr(); ++ } ++ ++ ++ virtual void ReadLink(const char* Linkname, ++ char*& LinkValue) { ++ errno = 0; ++ cout << "readlink\n"; ++ ThrowErr(); ++ } ++ ++ virtual FileServer_FileStatus GetStatus(const char* Filename) { ++ errno = 0; ++ cout << "stat\n"; ++ FileServer_FileStatus Stat; ++ ThrowErr(); ++ return Stat; ++ } ++ ++ ++ virtual FileServer_FileStatus GetLinkStatus(const char* Filename) { ++ errno = 0; ++ cout << "lstat\n"; ++ FileServer_FileStatus Stat; ++ ThrowErr(); ++ return Stat; ++ } ++ ++ ++ virtual void MakeDirectory(const char* PathName, ++ CORBA_Short mode) { ++ errno = 0; ++ cout << "mkdir\n"; ++ ThrowErr(); ++ } ++ ++ virtual void RemoveDirectory(const char* PathName) { ++ errno = 0; ++ cout << "rmdir\n"; ++ ThrowErr(); ++ } ++ ++ ++ virtual char* ChangeDirectory(const char* PathName) { ++ errno = 0; ++ cout << "chdir\n"; ++ ThrowErr(); ++ return CORBA_string_dup("hello"); ++ } ++ ++ virtual void MakeNode(const char* FileName, ++ CORBA_Short Mode, ++ CORBA_Long DeviceNum) { ++ errno = 0; ++ cout << "mknod\n"; ++ ThrowErr(); ++ } ++ ++ ++ virtual void Mount(const char* DeviceFile, ++ const char* Location, ++ const char* FSType, ++ CORBA_Long Flags) { ++ errno = 0; ++ cout << "Mount\n"; ++ ThrowErr(); ++ } ++ ++ virtual void Unmount(const char* Filename) { ++ errno = 0; ++ cout << "Unmount\n"; ++ ThrowErr(); ++ } ++}; ++ ++ ++int main(int argc, char* argv[]) { ++ cout << "FileServer UserSpace Server initializing" << endl; ++ ++ try { ++ CORBA_ORB_var orb = CORBA_ORB_init(argc, argv); ++ CORBA_BOA_var boa = orb->BOA_init(argc, argv); ++ ++ FileServer_FileSystem_var FS = new FileServer_impl(); ++ ++ cout << orb->object_to_string(FS) << endl; ++ ++ // ++ // Run implementation ++ // ++ boa -> impl_is_ready(CORBA_ImplementationDef::_nil()); ++ } catch(CORBA_SystemException& ex) { ++ OBPrintException(ex); ++ return 1; ++ } ++} +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/Makefile Thu Feb 1 11:47:08 2001 +@@ -0,0 +1,29 @@ ++CC = CC -mt -pta ++OBDIR = /home/class/cs423/local ++IDL = $(OBDIR)/bin/idl ++CPPFLAGS = -I. -I$(OBDIR)/include ++LDFLAGS = -L$(OBDIR)/lib ++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4 ++ ++all: FileServer ++ ++FileServer: FileServer.o FileServer-server.o FileServer_skel.o ++ $(CC) $(LDFLAGS) -o FileServer FileServer-server.o FileServer.o FileServer_skel.o $(LIBS) ++ ++FileServer.h FileServer.cpp: ../FileServer.idl ++ rm -f FileServer.cpp FileServer.h ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ $(IDL) ../FileServer.idl ++ ++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp ++ ++%.o: %.cpp ++ $(CC) $(CPPFLAGS) -c $< ++ ++clean: ++ rm -f FileServer *.o *~ ++ ++realclean: clean ++ rm -f FileServer.h FileServer.cpp ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ rm -rf SunWS_cache +diff -urN linux-2.4.1/net/korbit/modules/FileServer/server-user/README linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README +--- linux-2.4.1/net/korbit/modules/FileServer/server-user/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/server-user/README Thu Feb 1 11:47:08 2001 +@@ -0,0 +1 @@ ++This is a user space implementation of the FileServer interface. +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Entries Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,6 @@ ++/FileServer_wrapper.cpp/1.2/Thu Feb 1 09:47:09 2001// ++/FileServer_wrapper.h/1.2/Thu Feb 1 09:47:09 2001// ++/Makefile/1.1/Thu Feb 1 09:47:09 2001// ++/README/1.1/Thu Feb 1 09:47:09 2001// ++/test.c/1.2/Thu Feb 1 09:47:09 2001// ++D +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Repository Thu Feb 1 11:47:09 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/FileServer/wrapper +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/CVS/Root Thu Feb 1 11:47:09 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.cpp Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,135 @@ ++/* ++ * FileServer_wrapper.cpp ++ * ++ * We want to intercept *all* file I/O, so that once the LD_PRELOAD ++ * variable is set, everything you see is on the remote side. ++ * ++ * Needed environment variables: ++ * LD_PRELOAD - duh (what's the lib name?) ++ * KORBIT_IOR - IOR of the file servin' ORB to connect to. ++ * ++ */ ++ ++#include <stdio.h> ++#include <dlfcn.h> ++#include <stdarg.h> ++#include <stdlib.h> ++#include <string.h> ++#include <dirent.h> ++#include <errno.h> ++ ++#include "OB/CORBA.h" ++//#include "OB/Util.h" ++//#include "OB/CosNaming.h" ++ ++#include "FileServer.h" ++#include "FileServer_wrapper.h" ++ ++#define DEBUG ++ ++#ifdef DEBUG ++#define debugOut(X) cerr << X << flush; ++#else ++#define debugOut(X) ++#endif ++ ++ ++FileSystemState::FileSystemState() { ++ char *argv[] = { (char*)"/usr/bin/mkdir", 0 }; ++ int argc = 1; ++ ++ debugOut ("FS_wrapper: InitializeOrb(): start.\n"); ++ ++ /* Set 'PerformingInitialization = true'? */ ++ ++ orb = CORBA_ORB_init(argc, argv); ++ if (CORBA_is_nil(orb)) { ++ cerr << "Error initializing ORB!\n"; ++ exit(1); ++ } ++ debugOut ("\tORB initialized successfully.\n"); ++ ++ const char *env = getenv("KORBIT_IOR"); ++ if (!env) { ++ // This should check /proc/corba/FileServer-server also! ++ cerr << "InitializeOrb Error: KORBIT_IOR not found in environment!\n"; ++ exit(1); ++ } ++ ++ cout << "IOR = " << env << endl; ++ ++ // WHY DO I HANG IN string_to_object?? ++ CORBA_Object_var obj = orb->string_to_object(env); ++ debugOut("\tORB initialized successfully.\n"); ++ ++ if (CORBA_is_nil(obj)) { ++ cerr << "InitializeOrb Error: IOR is invalid: " << env << endl; ++ exit (1); ++ } ++ ++ debugOut ("\tORB initialized successfully.\n"); ++ try { ++ FS = FileServer_FileSystem::_narrow(obj); ++ } catch (...) { ++ cerr << "InitializeOrb Error: Got an exception from _narrow().\n"; ++ exit (1); ++ } ++ ++ /* Initialize my data structure 'o file descriptors. */ ++ ++ // Set up mapping for stdin, stdout, stderr. Set up a new fd, #4 for ++ // console/debug output ++ ++ // stderr can go to console for now. ++ ++ debugOut ("FS_wrapper: InitializeOrb(): finished successfully.\n"); ++} /* End InitializeOrb(). */ ++ ++ ++FileSystemState::~FileSystemState() (void) { ++} /* End CleanupOrb(). */ ++ ++ ++void HandleException(CORBA_UserException &Exception) { ++ try { ++ throw Exception; // get the type back... ++ } catch (Errors::FileExists &) { ++ errno = EEXIST; ++ } catch (Errors::PermissionDenied &) { ++ errno = EACCES; ++ } catch (Errors::FileNotFound &) { ++ errno = ENOENT; ++ } catch (Errors::IsNotDirectory &) { ++ errno = ENOTDIR; ++ } catch (Errors::ReadOnlyFile &) { ++ errno = EROFS; ++ } catch (Errors::RecursiveSymlink &) { ++ errno = ELOOP; ++ } catch (Errors::OtherError &) { ++ errno = EIO; /* I/O error */ ++ } catch (CORBA_UserException &Exception) { ++ cerr << "unknown exception occurred! \n"; ++ } ++} ++ ++//int open(const char *path, int oflag, mode_t mode) { ++ ++ ++// return -1; ++//} ++ ++int mkdir(const char *pathname, mode_t mode) { ++ debugOut("FS_wrapper: mkdir(" << pathname << "): start.\n"); ++ ++ try { ++ FileSystemState::get().getFS()->MakeDirectory(pathname, mode); ++ } catch (CORBA_UserException &ex) { ++ HandleException(ex); ++ return -1; ++ } ++ ++ // Success! ++ debugOut("FS wrapper: mkdir(): finish successfully.\n"); ++ return 0; ++} // End mkdir() ++ +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/FileServer_wrapper.h Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,81 @@ ++// The KORBit FileServer wrapper, which is a shared library that gets ++// hit with the LD_PRELOAD action, so as to redirect all FS calls ++// out the CORBA hole. ++// ++// Note that most of these functions have the side effect of modifying errno. ++// ++#ifndef FILESERVER_WRAPPER_H ++#define FILESERVER_WRAPPER_H ++ ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++ ++// This class contains all the global variables for this file. It is very ++// important that we use this mechanism so that our library is initialized as ++// early as possible, but no earlier. In particular this means that we cannot ++// be initialized before iostreams are, which we use for debugging. This scheme ++// the only way to that we are constructed and descructed on demand. ++// ++class FileSystemState { ++private: ++ FileSystemState(); // private ctor/dtor. The only way to get one of these is ++ ~FileSystemState(); // to call FileSystemState::get() ++ ++ FileSystemState(const FileSystemState &); // do not implement ++ FileSystemState &operator=(const FileSystemState &); // do not implement ++ ++ ++ CORBA_ORB_var orb; // Global reference to the orb. ++ FileServer_FileSystem_var FS; // Global reference to FS object... ++public: ++ static FileSystemState &get() { ++ // Static objects like this are intialized the first time they are used, and ++ // destroyed when the project shuts down. This is exactly the semantics we ++ // want. ++ static FileSystemState FSS; ++ return FSS; ++ } ++ ++ CORBA_ORB_var getORB() { return orb; } ++ FileServer_FileSystem_var getFS() { return FS; } ++}; ++ ++extern "C" { ++ ++ // ++ // interface File ++ // ++ // pread, readv, pwrite, writev ++ int read(int FD, void *Buffer, size_t NumBytes); ++ int write(int FD, void *Buffer, size_t NumBytes); ++ int close(int FD); ++ // fcntl ++ // fstat ++ // fchdir ++ // seek ++ int dup(int FD); ++ int dup2(int FDFrom, int FDTo); ++ ++ // ++ // interface FileSystem ++ // ++ // int open(const char *path, int oflag, mode_t mode); ++ int creat(const char *path, mode_t mode); ++ ++// link ++// unlink ++// rename ++// readlink ++// stat ++// lstat ++ int mkdir(const char *Path, mode_t Mode); ++// rmdir ++ int chdir(const char *Path); ++} ++ ++// ++// Local function prototypes. ++// ++ ++#endif +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/Makefile Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,29 @@ ++CC = CC -mt -pta -g ++OBDIR = /home/class/cs423/local ++IDL = $(OBDIR)/bin/idl ++CPPFLAGS = -I. -I$(OBDIR)/include ++LDFLAGS = -L$(OBDIR)/lib -G -fPIC ++LIBS = -lCosNaming -lOB -lJTC -lsocket -lnsl -lposix4 -lCstd -lCrun ++ ++all: libfswrapper.so ++ ++libfswrapper.so: FileServer.o FileServer_wrapper.o ++ CC $(LDFLAGS) -o $@ FileServer_wrapper.o FileServer.o $(LIBS) ++ ++FileServer.h FileServer.cpp: ../FileServer.idl ++ rm -f FileServer.cpp FileServer.h ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ $(IDL) ../FileServer.idl ++ ++FileServer_skel.cpp FileServer_skel.h: FileServer.cpp ++ ++%.o: %.cpp ++ $(CC) $(CPPFLAGS) -c $< ++ ++clean: ++ rm -f libfswrapper.so *.o *~ ++ ++realclean: clean ++ rm -f FileServer.h FileServer.cpp ++ rm -f FileServer_skel.h FileServer_skel.cpp ++ rm -rf SunWS_cache +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/README linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/README Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,5 @@ ++This is a library that may be LD_PRELOAD'd to forward filesystem related calls ++through the FileServer interface. ++ ++ORB: ORBacus ++Status: Mostly not working +diff -urN linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c +--- linux-2.4.1/net/korbit/modules/FileServer/wrapper/test.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/FileServer/wrapper/test.c Thu Feb 1 11:47:09 2001 +@@ -0,0 +1,15 @@ ++#include <stdlib.h> ++#include <stdio.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++ ++int main(void) ++{ ++ if (mkdir("test", 0666) == -1) ++ { ++ perror ("mkdir failed because: "); ++ return (1); ++ } ++ ++ return (0); ++} +diff -urN linux-2.4.1/net/korbit/modules/Makefile linux-2.4.1-korbit/net/korbit/modules/Makefile +--- linux-2.4.1/net/korbit/modules/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Makefile Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,15 @@ ++# ++# Makefile for KORBit/modules ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++subdir-$(CONFIG_CORBA_CONSOLE) += Console ++subdir-$(CONFIG_CORBA_ECHO) += Echo ++subdir-$(CONFIG_CORBA_FILESERVER) += FileServer ++subdir-$(CONFIG_CORBA_CORBAFS) += CorbaFS ++subdir-$(CONFIG_CORBA_CHARDEV) += CharDev ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/Makefile.module linux-2.4.1-korbit/net/korbit/modules/Makefile.module +--- linux-2.4.1/net/korbit/modules/Makefile.module Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/Makefile.module Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,9 @@ ++M_OBJS := $(O_TARGET) ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I../../.. -I../../../include -I../../../kglib -nostdinc ++ ++ ++ORBIT_IDL = orbit-idl ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/modules/README linux-2.4.1-korbit/net/korbit/modules/README +--- linux-2.4.1/net/korbit/modules/README Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/README Thu Feb 1 11:46:58 2001 +@@ -0,0 +1,7 @@ ++Modules included so far: ++ ++CharDev : Implement Linux character device drivers ++Console : Print strings to the Linux console ++CorbaFS : Implement Linux filesystems through the VFS layer ++Echo : Testcase to test orb two-way communication ++FileServer: Access a filesystem through CORBA +diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries +--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries Thu Feb 1 11:47:09 2001 +@@ -0,0 +1 @@ ++D +diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log +--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Entries.Log Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Entries.Log Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++A D/client//// +diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository +--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Repository Thu Feb 1 11:47:09 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/UserFS +diff -urN linux-2.4.1/net/korbit/modules/UserFS/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root +--- linux-2.4.1/net/korbit/modules/UserFS/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/CVS/Root Thu Feb 1 11:47:09 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries +--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Entries Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++D +diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository +--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Repository Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/modules/UserFS/client +diff -urN linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root +--- linux-2.4.1/net/korbit/modules/UserFS/client/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/modules/UserFS/client/CVS/Root Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/orb/CVS/Entries linux-2.4.1-korbit/net/korbit/orb/CVS/Entries +--- linux-2.4.1/net/korbit/orb/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Entries Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,60 @@ ++/Makefile/1.6/Thu Feb 1 09:47:10 2001// ++/allocator-defs.h/1.1.1.1/Thu Feb 1 09:47:10 2001// ++/allocators.c/1.2/Thu Feb 1 09:47:10 2001// ++/allocators.h/1.1.1.1/Thu Feb 1 09:47:10 2001// ++/cdr.c/1.1.1.1/Thu Feb 1 09:47:10 2001// ++/cdr.h/1.1.1.1/Thu Feb 1 09:47:10 2001// ++/corba_any.c/1.3/Thu Feb 1 09:47:10 2001// ++/corba_any.h/1.1.1.1/Thu Feb 1 09:47:10 2001// ++/corba_any_proto.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_any_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_basic_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_context.c/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_context.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_env.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_env_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_object.c/1.7/Thu Feb 1 09:47:11 2001// ++/corba_object.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_object_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_orb.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_orb_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_portableserver.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_portableserver_type.h/1.1.1.1/Thu Feb 1 09:47:11 2001// ++/corba_sequences.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/corba_sequences_type.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/corba_typecode.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/corba_typecode_type.h/1.3/Thu Feb 1 09:47:12 2001// ++/dii.c/1.2/Thu Feb 1 09:47:12 2001// ++/dii.h/1.2/Thu Feb 1 09:47:12 2001// ++/env.c/1.2/Thu Feb 1 09:47:12 2001// ++/env.h/1.2/Thu Feb 1 09:47:12 2001// ++/genrand.c/1.4/Thu Feb 1 09:47:12 2001// ++/genrand.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/iop.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/ir.c/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/ir.h/1.1.1.1/Thu Feb 1 09:47:12 2001// ++/options.c/1.2/Thu Feb 1 09:47:12 2001// ++/options.h/1.2/Thu Feb 1 09:47:13 2001// ++/orb.c/1.13/Thu Feb 1 09:47:13 2001// ++/orb.h/1.2/Thu Feb 1 09:47:13 2001// ++/orbit.c/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit.h/1.2/Thu Feb 1 09:47:13 2001// ++/orbit.h.in/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_config.h/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_object.c/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_object.h/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_object_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_poa.c/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_poa.h/1.3/Thu Feb 1 09:47:13 2001// ++/orbit_poa_type.h/1.1.1.1/Thu Feb 1 09:47:13 2001// ++/orbit_typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/orbit_typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/orbit_types.h/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/poa.c/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/poa.h/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/sequences.c/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/sequences.h/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/server.c/1.5/Thu Feb 1 09:47:14 2001// ++/typecode.c/1.1.1.1/Thu Feb 1 09:47:14 2001// ++/typecode.h/1.1.1.1/Thu Feb 1 09:47:14 2001// ++D +diff -urN linux-2.4.1/net/korbit/orb/CVS/Repository linux-2.4.1-korbit/net/korbit/orb/CVS/Repository +--- linux-2.4.1/net/korbit/orb/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Repository Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/orb +diff -urN linux-2.4.1/net/korbit/orb/CVS/Root linux-2.4.1-korbit/net/korbit/orb/CVS/Root +--- linux-2.4.1/net/korbit/orb/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/CVS/Root Thu Feb 1 11:47:10 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit +diff -urN linux-2.4.1/net/korbit/orb/Makefile linux-2.4.1-korbit/net/korbit/orb/Makefile +--- linux-2.4.1/net/korbit/orb/Makefile Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/Makefile Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,25 @@ ++# ++# Makefile for KORBit/orb ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .o file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++O_TARGET := orblib.o ++ ++#obj-m := $(O_TARGET) ++obj-y := allocators.o options.o poa.o \ ++ cdr.o env.o orb.o sequences.o \ ++ corba_any.o genrand.o orbit.o server.o \ ++ corba_context.o orbit_object.o typecode.o \ ++ corba_object.o orbit_poa.o \ ++ dii.o ir.o orbit_typecode.o ++ ++EXTRA_CFLAGS = -D__KORBIT__ -DHAVE_CONFIG_H -I. -I.. -I../include -I../kglib -I../ORBitutil -nostdinc \ ++ -DORBit_SYSRC=\"/etc/orbitrc\" \ ++ -DORBIT_MAJOR_VERSION="0" -DORBIT_MINOR_VERSION="5" -DORBIT_MICRO_VERSION="3" -DORBIT_VERSION=\"0.5.3\" ++ ++include $(TOPDIR)/Rules.make ++ +diff -urN linux-2.4.1/net/korbit/orb/allocator-defs.h linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h +--- linux-2.4.1/net/korbit/orb/allocator-defs.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/allocator-defs.h Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,40 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */ ++ ++ ++/******************************************************** ++ * Never include this header file directly. Only allocators.[ch] ++ * should do this ++ ********************************************************/ ++ ++/* Macro crap */ ++ ++#ifdef ALLOCATOR_DEFINITION ++ ++#define ORBIT_DEFINE_CHUNK(x, xsize) \ ++DEFINE_LOCK(x##_allocator); \ ++GMemChunk *x##_allocator = NULL ++ ++#elif defined(ALLOCATOR_INITIALIZATION) ++ ++#define ORBIT_DEFINE_CHUNK(x, xsize) INIT_LOCK(x##_allocator); \ ++x##_allocator = g_mem_chunk_new(#x, (xsize), \ ++(xsize) * ORBIT_CHUNKS_PREALLOC, G_ALLOC_AND_FREE) ++ ++#else ++ ++#define ORBIT_DEFINE_CHUNK(x, xsize) \ ++EXTERN_LOCK(x##_allocator); \ ++extern GMemChunk *x##_allocator ++ ++#endif ++ ++/***************************************************** ++ * Here's where we define the actual chunks that are used ++ *****************************************************/ ++ORBIT_DEFINE_CHUNK(CORBA_TypeCode, sizeof(struct CORBA_TypeCode_struct)); ++ORBIT_DEFINE_CHUNK(CORBA_Object, sizeof(struct CORBA_Object_struct)); ++ORBIT_DEFINE_CHUNK(CORBA_NVList, sizeof(struct CORBA_NVList_type)); ++ ++#undef ORBIT_DEFINE_CHUNK +diff -urN linux-2.4.1/net/korbit/orb/allocators.c linux-2.4.1-korbit/net/korbit/orb/allocators.c +--- linux-2.4.1/net/korbit/orb/allocators.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/allocators.c Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,241 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */ ++ ++#include "orbit.h" ++ ++#if 0 ++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); }) ++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); }) ++#endif ++ ++/* The memory chunk stuff */ ++ ++#define ALLOCATOR_DEFINITION ++#include "allocator-defs.h" ++#undef ALLOCATOR_DEFINITION ++ ++void ++ORBit_chunks_init(void) ++{ ++#define ALLOCATOR_INITIALIZATION ++#include "allocator-defs.h" ++#undef ALLOCATOR_INTIALIZATION ++} ++ ++gpointer ++ORBit_chunk_alloc(GMemChunk *chunk, ++ PARAM_LOCK(chunk)) ++{ ++ gpointer retval; ++ ++ GET_LOCK(chunk); ++ retval = g_mem_chunk_alloc(chunk); ++ RELEASE_LOCK(chunk); ++ ++ return retval; ++} ++ ++void ++ORBit_chunk_free(GMemChunk *chunk, ++ PARAM_LOCK(chunk), ++ gpointer mem) ++{ ++ GET_LOCK(chunk); ++ g_mem_chunk_free(chunk, mem); ++ RELEASE_LOCK(chunk); ++} ++ ++/* end memory chunk routines */ ++ ++/****************************************************************/ ++ ++/************* begin funky memory alloc/free system */ ++ ++/****** functions */ ++ ++gpointer ORBit_alloc(size_t block_size, ++ ORBit_free_childvals freefunc, ++ gpointer func_data) ++{ ++ return ORBit_alloc_2(block_size, freefunc, func_data, 0); ++} ++ ++gpointer ++ORBit_alloc_2(size_t block_size, ++ ORBit_free_childvals freefunc, ++ gpointer func_data, ++ size_t before_size) ++{ ++ ORBit_mem_info *block; ++ ++ if(block_size == 0) return NULL; ++ ++ block = (ORBit_mem_info *)((char *) ++ g_malloc(block_size + sizeof(ORBit_mem_info) + before_size) ++ + before_size); ++ ++#ifdef ORBIT_DEBUG ++ block->magic = 0xdeadbeef; ++#endif ++ block->free = freefunc; ++ block->func_data = func_data; ++ ++ return MEMINFO_TO_PTR(block); ++} ++ ++/* ++ ORBit_free ++ ---------- ++ ++ Frees a corba primitive type. ++ ++ mem = pointer to the memory block. (must have a preceeding pointer to a meminfo block) ++ ++ 1)obtains a pointer to the preceeding meminfo structure ++ 2)Uses the meminfo structure to find the number of elements in the memory block ++ 3)iterates through the memory block, calling the free function for each item. ++ ++ */ ++ ++void ++ORBit_free(gpointer mem, CORBA_boolean free_strings) ++{ ++ ORBit_mem_info *block; ++ ++ if(!mem) ++ return; ++ ++ block = PTR_TO_MEMINFO(mem); ++ ++#ifdef ORBIT_DEBUG ++ g_assert(block->magic == 0xdeadbeef); ++#endif ++ ++ if(block->free) { ++ int i; ++ gpointer x; ++ gpointer my_data; ++ ++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode) ++ my_data = ((guchar *)block) - sizeof(CORBA_TypeCode); ++ else ++ my_data = NULL; ++ ++#ifdef ORBIT_DEBUG ++ if(block->func_data == NULL) ++ g_warning("block with freefunc %p has no items", block->free); ++#endif ++ ++ for(i = 0, x = mem; i < (gulong)block->func_data; i++) ++ x = block->free(x, my_data, free_strings); ++ ++ if((gpointer)block->free == (gpointer)ORBit_free_via_TypeCode) ++ /* ((guchar *)block) -= sizeof(CORBA_TypeCode); */ ++ block = (ORBit_mem_info *) ++ (((guchar *)block) - sizeof(CORBA_TypeCode)); ++ g_free(block); ++ } else ++ g_free(block); ++} ++ ++/******************************************************************/ ++/* These aren't currently used... */ ++ ++gpointer ++ORBit_free_via_TypeCode(gpointer mem, gpointer tcp, gboolean free_strings) ++{ ++ CORBA_TypeCode tc = *(CORBA_TypeCode *)tcp, subtc; ++ int i; ++ guchar *retval = NULL; ++ ++ switch(tc->kind) { ++ case CORBA_tk_any: ++ { ++ CORBA_any *anyval = mem; ++ if(anyval->_release) ++ CORBA_free(anyval->_value); ++ retval = (guchar *)(anyval + 1); ++ } ++ break; ++ case CORBA_tk_TypeCode: ++ case CORBA_tk_objref: ++ { ++ CORBA_Object_release(*(CORBA_Object *)mem, NULL); ++ ++ retval = (guchar *)mem + sizeof(CORBA_Object); ++ } ++ break; ++ case CORBA_tk_Principal: ++ { ++ CORBA_Principal *pval = mem; ++ if(pval->_release) ++ CORBA_free(pval->_buffer); ++ retval = (guchar *)(pval + 1); ++ } ++ break; ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++ mem = ALIGN_ADDRESS(mem, ORBit_find_alignment(tc)); ++ for(i = 0; i < tc->sub_parts; i++) { ++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[i], NULL); ++ mem = ORBit_free_via_TypeCode(mem, &subtc, ++ free_strings); ++ } ++ retval = mem; ++ break; ++ case CORBA_tk_union: ++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate( ++ (CORBA_Object)ORBit_get_union_tag(tc, &mem, TRUE), NULL); ++ { ++ int sz = 0; ++ int al = 1; ++ for(i = 0; i < tc->sub_parts; i++) { ++ al = MAX(al, ORBit_find_alignment(tc->subtypes[i])); ++ sz = MAX(sz, ORBit_gather_alloc_info(tc->subtypes[i])); ++ } ++ mem = ALIGN_ADDRESS(mem, al); ++ ORBit_free_via_TypeCode(mem, &subtc, free_strings); ++ /* the end of the body (subtc) may not be the ++ * same as the end of the union */ ++ retval = mem + sz; ++ } ++ break; ++ case CORBA_tk_wstring: ++ case CORBA_tk_string: ++ if(free_strings) ++ CORBA_free(*(char **)mem); ++ retval = (guchar *)mem + sizeof(char *); ++ break; ++ case CORBA_tk_sequence: ++ { ++ CORBA_sequence_octet *pval = mem; ++ if(pval->_release) ++ CORBA_free(pval->_buffer); ++ ++ retval = (guchar *)mem + sizeof(CORBA_sequence_octet); ++ } ++ break; ++ case CORBA_tk_array: ++ for(i = 0; i < tc->length; i++) { ++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL); ++ mem = ORBit_free_via_TypeCode(mem, &subtc, ++ free_strings); ++ } ++ retval = mem; ++ break; ++ case CORBA_tk_alias: ++ subtc = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc->subtypes[0], NULL); ++ retval = ORBit_free_via_TypeCode(mem, &subtc, free_strings); ++ break; ++ default: ++ retval = ((guchar *)mem) + ORBit_gather_alloc_info(tc); ++ break; ++ } ++ ++ CORBA_Object_release((CORBA_Object)tc, NULL); ++ ++ return (gpointer)retval; ++} +diff -urN linux-2.4.1/net/korbit/orb/allocators.h linux-2.4.1-korbit/net/korbit/orb/allocators.h +--- linux-2.4.1/net/korbit/orb/allocators.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/allocators.h Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,61 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* By Elliot Lee. Copyright (c) 1998 Red Hat Software */ ++ ++#ifndef ALLOCATORS_H ++#define ALLOCATORS_H 1 ++ ++#include <orb/orbit.h> ++ ++#include <orb/allocator-defs.h> ++ ++#define ORBIT_CHUNK_ALLOC(typename) \ ++ORBit_chunk_alloc(typename##_allocator, LOCK_NAME(typename##_allocator)) ++ ++#define ORBIT_CHUNK_FREE(typename, mem) \ ++ORBit_chunk_free(typename##_allocator, LOCK_NAME(typename##_allocator), (mem)) ++ ++void ORBit_chunks_init(void); ++ ++gpointer ORBit_chunk_alloc(GMemChunk *chunk, ++ PARAM_LOCK(chunk_lock)); ++ ++void ORBit_chunk_free(GMemChunk *chunk, ++ PARAM_LOCK(chunk_lock), ++ gpointer mem); ++ ++/* General memory allocation routines */ ++ ++#define PTR_TO_MEMINFO(x) (((ORBit_mem_info *)(x)) - 1) ++#define MEMINFO_TO_PTR(x) ((gpointer)((x) + 1)) ++ ++typedef gpointer (*ORBit_free_childvals)(gpointer mem, ++ gpointer func_data, ++ CORBA_boolean free_strings); ++ ++typedef struct { ++#ifdef ORBIT_DEBUG ++ gulong magic; ++#endif ++ /* If this routine returns FALSE, it indicates that it already free'd ++ the memory block itself */ ++ ORBit_free_childvals free; /* function pointer to free function */ ++ gpointer func_data; ++} ORBit_mem_info; ++ ++gpointer ORBit_alloc(size_t block_size, ++ ORBit_free_childvals freefunc, ++ gpointer func_data); ++gpointer ORBit_alloc_2(size_t block_size, ++ ORBit_free_childvals freefunc, ++ gpointer func_data, ++ size_t before_size); ++ ++void ORBit_free(gpointer mem, CORBA_boolean free_strings); ++ ++/* internal stuff */ ++gpointer ORBit_free_via_TypeCode(gpointer mem, ++ gpointer tcp, ++ gboolean free_strings); ++ ++#endif /* ALLOCATORS_H */ +diff -urN linux-2.4.1/net/korbit/orb/cdr.c linux-2.4.1-korbit/net/korbit/orb/cdr.c +--- linux-2.4.1/net/korbit/orb/cdr.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/cdr.c Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,643 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#include "config.h" ++#include "../IIOP/iiop-endianP.h" ++#include <stdlib.h> ++#include <string.h> ++#include <ctype.h> ++#include <assert.h> ++ ++#include "orbit.h" ++ ++#define CDR_GROW_AMOUNT 128 ++ ++static CORBA_boolean CDR_buffer_grow(CDR_Codec *codec, const unsigned int growth) ++{ ++ unsigned int real_growth; ++ div_t divvy; ++ ++ if(codec->release_buffer) { ++ divvy=div(growth, CDR_GROW_AMOUNT); ++ real_growth=CDR_GROW_AMOUNT * (divvy.quot+1); ++ ++ codec->buffer=(CORBA_octet *)g_realloc(codec->buffer, ++ codec->buf_len ++ +real_growth); ++ } ++ ++ return CORBA_TRUE; ++} ++ ++static void CDR_buffer_puts(CDR_Codec *codec, const void *data, const unsigned int len) ++{ ++ if(codec->wptr+len > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, len); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ memcpy(&codec->buffer[codec->wptr], data, len); ++ codec->wptr+=len; ++} ++ ++CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len) ++{ ++ if(codec->rptr+len > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_gets: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ memcpy(dest, &codec->buffer[codec->rptr], len); ++ codec->rptr+=len; ++ ++ return(CORBA_TRUE); ++} ++ ++static void CDR_buffer_put(CDR_Codec *codec, void *datum) ++{ ++ if(codec->wptr+1 > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, 1); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ codec->buffer[codec->wptr++]=*(unsigned char *)datum; ++} ++ ++static CORBA_boolean CDR_buffer_get(CDR_Codec *codec, void *dest) ++{ ++ if(codec->rptr+1 > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ *(CORBA_octet *)dest=codec->buffer[codec->rptr++]; ++ return(CORBA_TRUE); ++} ++ ++#ifdef lame_slow_code ++static void CDR_buffer_put2(CDR_Codec *codec, void *datum) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(codec->readonly!=CORBA_TRUE); ++ g_assert(codec->wptr<=codec->buf_len); ++ ++ align=((codec->wptr+1)&~1L); ++ ++ if(align+2 > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, align+2-codec->wptr); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ while(codec->wptr < align) { ++ codec->buffer[codec->wptr++]='\0'; ++ } ++ ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1]; ++} ++ ++static CORBA_boolean CDR_buffer_get2(CDR_Codec *codec, void *dest) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(dest!=NULL); ++ g_assert(codec->rptr<=codec->buf_len); ++ ++ align=((codec->rptr+1)&~1L); ++ ++ if(align+2 > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get2: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ codec->rptr=align; ++ ++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++]; ++ ++ return(CORBA_TRUE); ++} ++ ++static void CDR_buffer_put4(CDR_Codec *codec, void *datum) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(codec->readonly!=CORBA_TRUE); ++ g_assert(codec->wptr<=codec->buf_len); ++ ++ align=((codec->wptr+3)&~3L); ++ ++ if(align+4 > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, align+4-codec->wptr); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ while(codec->wptr < align) { ++ codec->buffer[codec->wptr++]='\0'; ++ } ++ ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3]; ++} ++ ++static CORBA_boolean CDR_buffer_get4(CDR_Codec *codec, void *dest) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(dest!=NULL); ++ g_assert(codec->rptr<=codec->buf_len); ++ ++ align=((codec->rptr+3)&~3L); ++ ++ if(align+4 > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get4: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ codec->rptr=align; ++ ++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++]; ++ ++ return(CORBA_TRUE); ++} ++ ++static void CDR_buffer_put8(CDR_Codec *codec, void *datum) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(codec->readonly!=CORBA_TRUE); ++ g_assert(codec->wptr<=codec->buf_len); ++ ++ align=((codec->wptr+7)&~7L); ++ ++ if(align+8 > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, align+8-codec->wptr); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ while(codec->wptr < align) { ++ codec->buffer[codec->wptr++]='\0'; ++ } ++ ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7]; ++} ++ ++#if 0 ++static CORBA_boolean CDR_buffer_get8(CDR_Codec *codec, void *dest) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(dest!=NULL); ++ g_assert(codec->rptr<=codec->buf_len); ++ ++ align=((codec->rptr+7)&~7L); ++ ++ if(align+8 > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get8: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ codec->rptr=align; ++ ++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++]; ++ ++ return(CORBA_TRUE); ++} ++#endif ++ ++static void CDR_buffer_put16(CDR_Codec *codec, void *datum) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(codec->readonly!=CORBA_TRUE); ++ g_assert(codec->wptr<=codec->buf_len); ++ ++ align=((codec->wptr+15)&~15L); ++ ++ if(align+16 > codec->buf_len) { ++ CORBA_boolean res=CDR_buffer_grow(codec, align+16-codec->wptr); ++ ++ if(res==CORBA_FALSE) { ++ /* just bail out for now */ ++ g_assert(!"Malloc error"); ++ } ++ } ++ ++ while(codec->wptr < align) { ++ codec->buffer[codec->wptr++]='\0'; ++ } ++ ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[0]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[1]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[2]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[3]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[4]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[5]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[6]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[7]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[8]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[9]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[10]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[11]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[12]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[13]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[14]; ++ codec->buffer[codec->wptr++]=((CORBA_octet *)datum)[15]; ++} ++ ++#if 0 ++static CORBA_boolean CDR_buffer_get16(CDR_Codec *codec, void *dest) ++{ ++ unsigned long align; ++ ++ g_assert(codec!=NULL); ++ g_assert(dest!=NULL); ++ g_assert(codec->rptr<=codec->buf_len); ++ ++ align=((codec->rptr+15)&~15L); ++ ++ if(align+16 > codec->buf_len) { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Debug, "CDR_buffer_get16: attempt to read past end of buffer\n"); ++ return(CORBA_FALSE); ++ } ++ ++ codec->rptr=align; ++ ++ ((CORBA_octet *)dest)[0]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[1]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[2]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[3]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[4]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[5]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[6]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[7]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[8]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[9]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[10]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[11]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[12]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[13]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[14]=codec->buffer[codec->rptr++]; ++ ((CORBA_octet *)dest)[15]=codec->buffer[codec->rptr++]; ++ ++ return(CORBA_TRUE); ++} ++#endif ++#endif /* lame_slow_code */ ++ ++#define CDR_buffer_put2(codec, datum) CDR_buffer_putn(codec, datum, 2) ++#define CDR_buffer_put4(codec, datum) CDR_buffer_putn(codec, datum, 4) ++#define CDR_buffer_put8(codec, datum) CDR_buffer_putn(codec, datum, 8) ++#define CDR_buffer_put16(codec, datum) CDR_buffer_putn(codec, datum, 16) ++#define CDR_buffer_get2(codec, dest) CDR_buffer_getn(codec, dest, 2) ++#define CDR_buffer_get4(codec, dest) CDR_buffer_getn(codec, dest, 4) ++#define CDR_buffer_get8(codec, dest) CDR_buffer_getn(codec, dest, 8) ++#define CDR_buffer_get16(codec, dest) CDR_buffer_getn(codec, dest, 16) ++ ++static CORBA_boolean ++CDR_buffer_getn(CDR_Codec *codec, void *dest, int bsize) ++{ ++ codec->rptr = (unsigned long)ALIGN_ADDRESS(codec->rptr, bsize); ++ if(codec->host_endian==codec->data_endian) ++ memcpy(dest, codec->buffer + codec->rptr, bsize); ++ else ++ iiop_byteswap(dest, codec->buffer + codec->rptr, bsize); ++ codec->rptr += bsize; ++ ++ return CORBA_TRUE; ++} ++ ++static CORBA_boolean ++CDR_buffer_putn(CDR_Codec *codec, void *datum, int bsize) ++{ ++ codec->wptr = (unsigned long)ALIGN_ADDRESS(codec->wptr, bsize); ++ if(codec->host_endian==codec->data_endian) ++ memcpy(codec->buffer + codec->wptr, datum, bsize); ++ else ++ iiop_byteswap(codec->buffer + codec->wptr, datum, bsize); ++ codec->wptr += bsize; ++ ++ return CORBA_TRUE; ++} ++ ++#define CDR_swap2(d,s) iiop_byteswap((d), (s), 2) ++#define CDR_swap4(d,s) iiop_byteswap((d), (s), 4) ++#define CDR_swap8(d,s) iiop_byteswap((d), (s), 8) ++#define CDR_swap16(d,s) iiop_byteswap((d), (s), 16) ++ ++#ifdef lame_slow_code ++static void CDR_swap2(void *d, void *s) ++{ ++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[1]; ++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[0]; ++} ++ ++static void CDR_swap4(void *d, void *s) ++{ ++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[3]; ++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[2]; ++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[1]; ++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[0]; ++} ++ ++static void CDR_swap8(void *d, void *s) ++{ ++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[7]; ++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[6]; ++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[5]; ++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[4]; ++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[3]; ++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[2]; ++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[1]; ++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[0]; ++} ++ ++static void CDR_swap16(void *d, void *s) ++{ ++ ((CORBA_octet *)d)[0]=((CORBA_octet *)s)[15]; ++ ((CORBA_octet *)d)[1]=((CORBA_octet *)s)[14]; ++ ((CORBA_octet *)d)[2]=((CORBA_octet *)s)[13]; ++ ((CORBA_octet *)d)[3]=((CORBA_octet *)s)[12]; ++ ((CORBA_octet *)d)[4]=((CORBA_octet *)s)[11]; ++ ((CORBA_octet *)d)[5]=((CORBA_octet *)s)[10]; ++ ((CORBA_octet *)d)[6]=((CORBA_octet *)s)[9]; ++ ((CORBA_octet *)d)[7]=((CORBA_octet *)s)[8]; ++ ((CORBA_octet *)d)[8]=((CORBA_octet *)s)[7]; ++ ((CORBA_octet *)d)[9]=((CORBA_octet *)s)[6]; ++ ((CORBA_octet *)d)[10]=((CORBA_octet *)s)[5]; ++ ((CORBA_octet *)d)[11]=((CORBA_octet *)s)[4]; ++ ((CORBA_octet *)d)[12]=((CORBA_octet *)s)[3]; ++ ((CORBA_octet *)d)[13]=((CORBA_octet *)s)[2]; ++ ((CORBA_octet *)d)[14]=((CORBA_octet *)s)[1]; ++ ((CORBA_octet *)d)[15]=((CORBA_octet *)s)[0]; ++} ++#endif ++ ++ ++void CDR_put_short(CDR_Codec *codec, CORBA_short s) ++{ ++ CDR_buffer_put2(codec, &s); ++} ++ ++CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *s) ++{ ++ return CDR_buffer_get2(codec, s); ++} ++ ++void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us) ++{ ++ CDR_buffer_put2(codec, &us); ++} ++ ++CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us) ++{ ++ return CDR_buffer_get2(codec, us); ++} ++ ++void CDR_put_long(CDR_Codec *codec, CORBA_long l) ++{ ++ CDR_buffer_put4(codec, &l); ++} ++ ++CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l) ++{ ++ return CDR_buffer_get4(codec, l); ++} ++ ++void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul) ++{ ++ CDR_buffer_put4(codec, &ul); ++} ++ ++CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul) ++{ ++ return CDR_buffer_get4(codec, ul); ++} ++ ++#ifdef HAVE_CORBA_LONG_LONG ++CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul) ++{ ++ return CDR_buffer_get8(codec, ul); ++} ++ ++void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll) ++{ ++ CDR_buffer_put8(codec, &ll); ++} ++ ++void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ll) ++{ ++ CDR_buffer_put8(codec, &ll); ++} ++ ++CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ull) ++{ ++ return CDR_buffer_get8(codec, ull); ++} ++#endif ++ ++void CDR_put_float(CDR_Codec *codec, CORBA_float f) ++{ ++ CDR_buffer_put4(codec, &f); ++} ++ ++void CDR_put_double(CDR_Codec *codec, CORBA_double d) ++{ ++ CDR_buffer_put8(codec, &d); ++} ++ ++void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld) ++{ ++ CDR_buffer_put16(codec, &ld); ++} ++ ++void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum) ++{ ++ CDR_buffer_put(codec, &datum); ++} ++ ++CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum) ++{ ++ return(CDR_buffer_get(codec, datum)); ++} ++ ++void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len) ++{ ++ CDR_buffer_puts(codec, data, len); ++} ++ ++void CDR_put_char(CDR_Codec *codec, CORBA_char c) ++{ ++ CDR_buffer_put(codec, &c); ++} ++ ++CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c) ++{ ++ return CDR_buffer_get(codec, c); ++} ++ ++void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum) ++{ ++ datum = datum&&1; ++ CDR_buffer_put(codec, &datum); ++} ++ ++CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b) ++{ ++ return CDR_buffer_get(codec, b); ++} ++ ++void CDR_put_string(CDR_Codec *codec, const char *str) ++{ ++ unsigned int len; ++ ++ len=strlen(str)+1; ++ ++ CDR_put_ulong(codec, len); ++ CDR_buffer_puts(codec, str, len); ++} ++ ++CORBA_boolean CDR_get_string_static(CDR_Codec *codec, ++ CORBA_char **str) ++{ ++ CORBA_unsigned_long len; ++ ++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE) ++ return CORBA_FALSE; ++ ++ if((codec->rptr + len) > codec->buf_len) ++ return CORBA_FALSE; ++ ++ *str = ((CORBA_char *)codec->buffer) + codec->rptr; ++ ++ codec->rptr += len; ++ ++ return CORBA_TRUE; ++} ++ ++CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str) ++{ ++ CORBA_unsigned_long len; ++ ++ if(CDR_get_ulong(codec, &len)==CORBA_FALSE) ++ return(CORBA_FALSE); ++ ++ if(len==0) ++ return(CORBA_FALSE); ++ ++ *str=g_new(CORBA_char, len); ++ ++ if(CDR_buffer_gets(codec, *str, len)==CORBA_FALSE) { ++ g_free(*str); ++ return(CORBA_FALSE); ++ } ++ ++ if((*str)[len-1]!='\0') { ++ ORBit_Trace(TraceMod_CDR, TraceLevel_Notice, "CDR_get_string: string was not NULL-terminated, terminating it now\n"); ++ (*str)[len-1]='\0'; ++ } ++ ++ return(CORBA_TRUE); ++} ++ ++CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul) ++{ ++ return(CDR_get_ulong(codec, ul)); ++} ++ ++CDR_Codec *CDR_codec_init_static(CDR_Codec *codec) ++{ ++ memset(codec, 0, sizeof(CDR_Codec)); ++ ++ codec->host_endian = FLAG_ENDIANNESS; ++ ++ return codec; ++} ++ ++CDR_Codec *CDR_codec_init(void) ++{ ++ CDR_Codec *new; ++ ++ new=g_new0(CDR_Codec, 1); ++ CDR_codec_init_static(new); ++ new->release_buffer = CORBA_TRUE; ++ ++ return(new); ++} ++ ++void CDR_codec_free(CDR_Codec *codec) ++{ ++ if(codec->release_buffer) ++ g_free(codec->buffer); ++ ++ g_free(codec); ++} +diff -urN linux-2.4.1/net/korbit/orb/cdr.h linux-2.4.1-korbit/net/korbit/orb/cdr.h +--- linux-2.4.1/net/korbit/orb/cdr.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/cdr.h Thu Feb 1 16:22:12 2001 +@@ -0,0 +1,83 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CDR_H_ ++#define _ORBIT_CDR_H_ ++ ++#include "orbit_types.h" ++ ++typedef enum { ++ BigEndian=0, ++ LittleEndian=1 ++} CDR_Endianness; ++ ++typedef struct { ++ CDR_Endianness host_endian; ++ CDR_Endianness data_endian; ++ CORBA_octet *buffer; ++ unsigned int buf_len; ++ unsigned int wptr, rptr; ++ CORBA_boolean readonly; ++ CORBA_boolean release_buffer; ++} CDR_Codec; ++ ++#define HEXDIGIT(c) (isdigit((guchar)(c))?(c)-'0':tolower((guchar)(c))-'a'+10) ++#define HEXOCTET(a,b) ((HEXDIGIT((a)) << 4) | HEXDIGIT((b))) ++ ++extern CDR_Codec *CDR_codec_init(void); ++extern CDR_Codec *CDR_codec_init_static(CDR_Codec *codec); ++extern void CDR_codec_free(CDR_Codec *); ++ ++extern void CDR_put_short(CDR_Codec *codec, CORBA_short s); ++extern void CDR_put_ushort(CDR_Codec *codec, CORBA_unsigned_short us); ++extern void CDR_put_long(CDR_Codec *codec, CORBA_long l); ++extern void CDR_put_ulong(CDR_Codec *codec, CORBA_unsigned_long ul); ++#ifdef HAVE_CORBA_LONG_LONG ++extern void CDR_put_long_long(CDR_Codec *codec, CORBA_long_long ll); ++extern void CDR_put_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long ull); ++extern CORBA_boolean CDR_get_ulong_long(CDR_Codec *codec, CORBA_unsigned_long_long *ul); ++extern CORBA_boolean CDR_get_long_long(CDR_Codec *codec, CORBA_long_long *ul); ++#endif ++extern void CDR_put_float(CDR_Codec *codec, CORBA_float f); ++extern void CDR_put_double(CDR_Codec *codec, CORBA_double d); ++extern void CDR_put_long_double(CDR_Codec *codec, CORBA_long_double ld); ++extern void CDR_put_octet(CDR_Codec *codec, CORBA_octet datum); ++extern void CDR_put_octets(CDR_Codec *codec, void *data, unsigned long len); ++extern void CDR_put_char(CDR_Codec *codec, CORBA_char c); ++extern void CDR_put_boolean(CDR_Codec *codec, CORBA_boolean datum); ++extern void CDR_put_string(CDR_Codec *codec, const char *str); ++extern CORBA_boolean CDR_buffer_gets(CDR_Codec *codec, void *dest, const unsigned int len); ++extern CORBA_boolean CDR_get_short(CDR_Codec *codec, CORBA_short *us); ++extern CORBA_boolean CDR_get_ushort(CDR_Codec *codec, CORBA_unsigned_short *us); ++extern CORBA_boolean CDR_get_long(CDR_Codec *codec, CORBA_long *l); ++extern CORBA_boolean CDR_get_ulong(CDR_Codec *codec, CORBA_unsigned_long *ul); ++extern CORBA_boolean CDR_get_octet(CDR_Codec *codec, CORBA_octet *datum); ++extern CORBA_boolean CDR_get_boolean(CDR_Codec *codec, CORBA_boolean *b); ++extern CORBA_boolean CDR_get_char(CDR_Codec *codec, CORBA_char *c); ++extern CORBA_boolean CDR_get_string(CDR_Codec *codec, CORBA_char **str); ++extern CORBA_boolean CDR_get_string_static(CDR_Codec *codec, CORBA_char **str); ++extern CORBA_boolean CDR_get_seq_begin(CDR_Codec *codec, CORBA_unsigned_long *ul); ++ ++#endif /* !_ORBIT_CDR_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_any.c linux-2.4.1-korbit/net/korbit/orb/corba_any.c +--- linux-2.4.1/net/korbit/orb/corba_any.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.c Thu Feb 1 11:47:10 2001 +@@ -0,0 +1,914 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++#include <config.h> ++#include <IIOP/IIOP.h> ++#include "orbit.h" ++ ++#if 0 ++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); }) ++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); }) ++#endif ++ ++gint ++ORBit_find_alignment(CORBA_TypeCode tc) ++{ ++ gint retval = 1; ++ int i; ++ ++ switch(tc->kind) { ++ case CORBA_tk_union: ++ retval = MAX(retval, ORBit_find_alignment(tc->discriminator)); ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++#if ALIGNOF_CORBA_STRUCT > 1 ++ retval = MAX(retval, ALIGNOF_CORBA_STRUCT); ++#endif ++ for(i = 0; i < tc->sub_parts; i++) ++ retval = MAX(retval, ORBit_find_alignment(tc->subtypes[i])); ++ return retval; ++ case CORBA_tk_ulong: ++ case CORBA_tk_long: ++ case CORBA_tk_enum: ++ return ALIGNOF_CORBA_LONG; ++ case CORBA_tk_ushort: ++ case CORBA_tk_short: ++ case CORBA_tk_wchar: ++ return ALIGNOF_CORBA_SHORT; ++ case CORBA_tk_longlong: ++ case CORBA_tk_ulonglong: ++ return ALIGNOF_CORBA_LONG_LONG; ++ case CORBA_tk_longdouble: ++ return ALIGNOF_CORBA_LONG_DOUBLE; ++ case CORBA_tk_float: ++ return ALIGNOF_CORBA_FLOAT; ++ case CORBA_tk_double: ++ return ALIGNOF_CORBA_DOUBLE; ++ case CORBA_tk_boolean: ++ case CORBA_tk_char: ++ case CORBA_tk_octet: ++ return ALIGNOF_CORBA_CHAR; ++ case CORBA_tk_string: ++ case CORBA_tk_wstring: ++ case CORBA_tk_TypeCode: ++ case CORBA_tk_objref: ++ return ALIGNOF_CORBA_POINTER; ++ case CORBA_tk_sequence: ++ case CORBA_tk_any: ++ return MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER); ++ case CORBA_tk_array: ++ case CORBA_tk_alias: ++ return ORBit_find_alignment(tc->subtypes[0]); ++ case CORBA_tk_fixed: ++ return MAX(ALIGNOF_CORBA_SHORT, ALIGNOF_CORBA_STRUCT); ++ default: ++ return 1; ++ } ++} ++ ++static void ++ORBit_marshal_value(GIOPSendBuffer *buf, ++ gpointer *val, ++ CORBA_TypeCode tc, ++ ORBit_marshal_value_info *mi) ++{ ++ CORBA_unsigned_long i, ulval; ++ gpointer subval; ++ ORBit_marshal_value_info submi; ++ ++#if 0 ++ g_message("Marshalling a %d value from %#x to offset %d", ++ tc->kind, (gulong)*val, ++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size); ++#endif ++ ++ switch(tc->kind) { ++ case CORBA_tk_wchar: ++ case CORBA_tk_ushort: ++ case CORBA_tk_short: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_short)); ++ *val = ((guchar *)*val) + sizeof(CORBA_short); ++ break; ++ case CORBA_tk_enum: ++ case CORBA_tk_long: ++ case CORBA_tk_ulong: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long)); ++ *val = ((guchar *)*val) + sizeof(CORBA_long); ++ break; ++ case CORBA_tk_float: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_float)); ++ *val = ((guchar *)*val) + sizeof(CORBA_float); ++ break; ++ case CORBA_tk_double: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_double)); ++ *val = ((guchar *)*val) + sizeof(CORBA_double); ++ break; ++ case CORBA_tk_boolean: ++ case CORBA_tk_char: ++ case CORBA_tk_octet: ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_octet)); ++ *val = ((guchar *)*val) + sizeof(CORBA_octet); ++ break; ++ case CORBA_tk_any: ++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER)); ++ ORBit_marshal_any(buf, *val); ++ *val = ((guchar *)*val) + sizeof(CORBA_any); ++ break; ++ case CORBA_tk_TypeCode: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ ORBit_encode_CORBA_TypeCode(*val, buf); ++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode); ++ break; ++ case CORBA_tk_Principal: ++ *val = ALIGN_ADDRESS(*val, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ++ ALIGNOF_CORBA_POINTER)); ++ ++ ulval = *(CORBA_unsigned_long *)(*val); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_unsigned_long)); ++ ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), ++ *(char**)((char *)*val+sizeof(CORBA_unsigned_long)), ++ ulval); ++ *val = ((guchar *)*val) + sizeof(CORBA_Principal); ++ break; ++ case CORBA_tk_objref: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ ORBit_marshal_object(buf, *val); ++ *val = ((guchar *)*val) + sizeof(CORBA_Object); ++ break; ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc)); ++ for(i = 0; i < tc->sub_parts; i++) { ++ ORBit_marshal_value(buf, val, tc->subtypes[i], mi); ++ } ++ break; ++ case CORBA_tk_union: ++ /* Basic algorithm: ++ marshal the discriminator ++ find out which value we want to use */ ++ { ++ CORBA_TypeCode utc; ++ ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT); ++ ++ utc = ORBit_get_union_tag(tc, val, TRUE); ++ ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT); ++ ++ ORBit_marshal_value(buf, val, tc->discriminator, mi); ++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc)); ++ ORBit_marshal_value(buf, val, utc, mi); ++ } ++ break; ++ case CORBA_tk_wstring: ++ ulval = strlen(*(char **)*val) + 1; ++ ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ giop_send_buffer_append_mem_indirect_a(buf, ++ &ulval, ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval); ++ ++ *val = ((guchar *)*val) + sizeof(char *); ++ break; ++ case CORBA_tk_string: ++ ulval = strlen(*(char **)*val) + 1; ++ ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ ++ giop_send_buffer_append_mem_indirect_a(buf, ++ &ulval, ++ sizeof(CORBA_unsigned_long)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), *(char **)*val, ulval); ++ ++ *val = ((guchar *)*val) + sizeof(char *); ++ break; ++ case CORBA_tk_sequence: ++ { ++ CORBA_sequence_octet *sval = *val; ++ ++ *val = ALIGN_ADDRESS(*val, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_STRUCT), ALIGNOF_CORBA_POINTER)); ++ ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), ++ &sval->_length, ++ sizeof(sval->_length)); ++ ++ subval = sval->_buffer; ++ ++ for(i = 0; i < sval->_length; i++) ++ ORBit_marshal_value(buf, &subval, tc->subtypes[0], mi); ++ ++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet); ++ } ++ break; ++ case CORBA_tk_array: ++ submi.alias_element_type = tc->subtypes[0]; ++ for(i = 0; i < tc->length; i++) { ++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi); ++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc->subtypes[0])); ++ } ++ break; ++ case CORBA_tk_alias: ++ submi.alias_element_type = tc->subtypes[0]; ++ ORBit_marshal_value(buf, val, submi.alias_element_type, &submi); ++ break; ++ case CORBA_tk_longlong: ++ case CORBA_tk_ulonglong: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_long)); ++ return /* *val + sizeof(CORBA_long_long)*/; ++ break; ++ case CORBA_tk_longdouble: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE); ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), *val, sizeof(CORBA_long_double)); ++ return /* *val + sizeof(CORBA_long_double)*/; ++ break; ++ case CORBA_tk_fixed: ++ /* XXX todo */ ++ g_error("CORBA_fixed NYI"); ++ ++ break; ++ case CORBA_tk_null: ++ case CORBA_tk_void: ++ break; ++ default: ++ g_error("Can't encode unknown type %d", tc->kind); ++ } ++} ++ ++static glong ORBit_get_union_switch(CORBA_TypeCode tc, gpointer *val, gboolean update) ++{ ++#ifdef __KORBIT__ ++ glong retval = 0; ++#else ++ glong retval; ++#endif ++ ++ switch(tc->kind) { ++ case CORBA_tk_ulong: ++ case CORBA_tk_long: ++ case CORBA_tk_enum: ++ retval = *(CORBA_long *)*val; ++ if(update) *val += sizeof(CORBA_long); ++ break; ++ case CORBA_tk_ushort: ++ case CORBA_tk_short: ++ retval = *(CORBA_short *)*val; ++ if(update) *val += sizeof(CORBA_short); ++ break; ++ case CORBA_tk_char: ++ case CORBA_tk_boolean: ++ case CORBA_tk_octet: ++ retval = *(CORBA_octet *)*val; ++ if(update) *val += sizeof(CORBA_char); ++ break; ++ case CORBA_tk_alias: ++ return ORBit_get_union_switch(tc->subtypes[0], val, update); ++ break; ++ default: ++ g_error("Wow, some nut has passed us a weird type[%d] as a union discriminator!", tc->kind); ++ } ++ ++ return retval; ++} ++ ++/* This function (and the one above it) exist for the ++ sole purpose of finding out which CORBA_TypeCode a union discriminator value ++ indicates. ++ ++ If {update} is TRUE, {*val} will be advanced by the native size ++ of the descriminator type. ++ ++ Hairy stuff. ++*/ ++CORBA_TypeCode ++ORBit_get_union_tag(CORBA_TypeCode union_tc, gpointer *val, gboolean update) ++{ ++ glong discrim_val, case_val; ++ int i; ++ CORBA_TypeCode retval = CORBA_OBJECT_NIL; ++ ++ discrim_val = ORBit_get_union_switch(union_tc->discriminator, val, update); ++ ++ for(i = 0; i < union_tc->sub_parts; i++) { ++ if(i == union_tc->default_index) ++ continue; ++ ++ case_val = ORBit_get_union_switch(union_tc->sublabels[i]._type, ++ &union_tc->sublabels[i]._value, FALSE); ++ if(case_val == discrim_val) { ++ retval = union_tc->subtypes[i]; ++ break; ++ } ++ } ++ ++ if(retval) ++ return retval; ++ else if(union_tc->default_index >= 0) ++ return union_tc->subtypes[union_tc->default_index]; ++ else { ++ return TC_null; ++ } ++} ++ ++void ++ORBit_marshal_arg(GIOPSendBuffer *buf, ++ gpointer val, ++ CORBA_TypeCode tc) ++{ ++ ORBit_marshal_value_info mi; ++ ++ ORBit_marshal_value(buf, &val, tc, &mi); ++} ++ ++ ++void ++ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val) ++{ ++ ORBit_marshal_value_info mi; ++ ++ gpointer mval = val->_value; ++ ++ ORBit_encode_CORBA_TypeCode(val->_type, buf); ++ ++ ORBit_marshal_value(buf, &mval, val->_type, &mi); ++} ++ ++size_t ++ORBit_gather_alloc_info(CORBA_TypeCode tc) ++{ ++ int i, n, align=1, prevalign, sum, prev; ++ size_t block_size; ++ ++ switch(tc->kind) { ++ case CORBA_tk_long: ++ case CORBA_tk_ulong: ++ case CORBA_tk_enum: ++ return sizeof(CORBA_long); ++ break; ++ case CORBA_tk_short: ++ case CORBA_tk_ushort: ++ return sizeof(CORBA_short); ++ break; ++ case CORBA_tk_float: ++ return sizeof(CORBA_float); ++ break; ++ case CORBA_tk_double: ++ return sizeof(CORBA_double); ++ break; ++ case CORBA_tk_boolean: ++ case CORBA_tk_char: ++ case CORBA_tk_octet: ++ return sizeof(CORBA_octet); ++ break; ++ case CORBA_tk_any: ++ return sizeof(CORBA_any); ++ break; ++ case CORBA_tk_TypeCode: ++ return sizeof(CORBA_TypeCode); ++ break; ++ case CORBA_tk_Principal: ++ return sizeof(CORBA_Principal); ++ break; ++ case CORBA_tk_objref: ++ return sizeof(CORBA_Object); ++ break; ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++ sum = 0; ++ for(i = 0; i < tc->sub_parts; i++) { ++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[i]))); ++ sum += ORBit_gather_alloc_info(tc->subtypes[i]); ++ } ++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc))); ++ return sum; ++ break; ++ case CORBA_tk_union: ++ sum = ORBit_gather_alloc_info(tc->discriminator); ++ n = -1; ++ align = 1; ++ for(prev = prevalign = i = 0; i < tc->sub_parts; i++) { ++ prevalign = align; ++ align = ORBit_find_alignment(tc->subtypes[i]); ++ if(align > prevalign) ++ n = i; ++ ++ prev = MAX(prev, ORBit_gather_alloc_info(tc->subtypes[i])); ++ } ++ if(n >= 0) ++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc->subtypes[n]))); ++ sum += prev; ++ sum = GPOINTER_TO_INT(ALIGN_ADDRESS(sum, ORBit_find_alignment(tc))); ++ return sum; ++ break; ++ case CORBA_tk_wstring: ++ case CORBA_tk_string: ++ return sizeof(char *); ++ break; ++ case CORBA_tk_sequence: ++ return sizeof(CORBA_sequence_octet); ++ break; ++ case CORBA_tk_array: ++ block_size = ORBit_gather_alloc_info(tc->subtypes[0]); ++ return block_size * tc->length; ++ break; ++ case CORBA_tk_alias: ++ return ORBit_gather_alloc_info(tc->subtypes[0]); ++ case CORBA_tk_longlong: ++ case CORBA_tk_ulonglong: ++ return sizeof(CORBA_long_long); ++ case CORBA_tk_longdouble: ++ return sizeof(CORBA_long_double); ++ case CORBA_tk_wchar: ++ return sizeof(CORBA_wchar); ++ case CORBA_tk_fixed: ++ return sizeof(CORBA_fixed_d_s); ++ default: ++ return 0; ++ } ++} ++ ++/* to allocate a block, we need to know of any important data ++ contained in it. ++*/ ++static gpointer ++ORBit_demarshal_allocate_mem(CORBA_TypeCode tc, gint nelements) ++{ ++ size_t block_size; ++ gpointer retval = NULL; ++ ++ if(!nelements) return retval; ++ ++ block_size = ORBit_gather_alloc_info(tc); ++ ++ if(block_size) { ++ retval = ORBit_alloc_2(block_size * nelements, ++ (ORBit_free_childvals)ORBit_free_via_TypeCode, ++ GINT_TO_POINTER(nelements), ++ sizeof(CORBA_TypeCode)); ++ ++ *(CORBA_TypeCode *)((char *)retval-sizeof(ORBit_mem_info)-sizeof(CORBA_TypeCode)) = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)tc, NULL); ++ } ++ ++ return retval; ++} ++ ++#define DM_GET_ATOM(x, n) G_STMT_START{ GIOP_RECV_BUFFER(buf)->decoder(x, (GIOP_RECV_BUFFER(buf)->cur), n); GIOP_RECV_BUFFER(buf)->cur = ((guchar *)GIOP_RECV_BUFFER(buf)->cur) + n; }G_STMT_END ++ ++static void ++ORBit_demarshal_value(GIOPRecvBuffer *buf, ++ gpointer *val, ++ CORBA_TypeCode tc, ++ gboolean dup_strings, ++ CORBA_ORB orb) ++{ ++ CORBA_long i, n; ++ ++#if 0 ++ g_message("Demarshalling a %d value from offset %d into %#x", ++ tc->kind, buf->cur - buf->message_body, (gulong)*val); ++#endif ++ ++ switch(tc->kind) { ++ case CORBA_tk_short: ++ case CORBA_tk_ushort: ++ case CORBA_tk_wchar: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_short)); ++ DM_GET_ATOM(*val, sizeof(CORBA_short)); ++ *val = ((guchar *)*val) + sizeof(CORBA_short); ++ break; ++ case CORBA_tk_long: ++ case CORBA_tk_ulong: ++ case CORBA_tk_enum: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long)); ++ DM_GET_ATOM(*val, sizeof(CORBA_long)); ++ *val = ((guchar *)*val) + sizeof(CORBA_long); ++ break; ++ case CORBA_tk_longlong: ++ case CORBA_tk_ulonglong: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_long)); ++ DM_GET_ATOM(*val, sizeof(CORBA_long_long)); ++ *val = ((guchar *)*val) + sizeof(CORBA_long_long); ++ break; ++ case CORBA_tk_longdouble: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long_double)); ++ DM_GET_ATOM(*val, sizeof(CORBA_long_double)); ++ *val = ((guchar *)*val) + sizeof(CORBA_long_double); ++ break; ++ case CORBA_tk_float: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_float)); ++ DM_GET_ATOM(*val, sizeof(CORBA_float)); ++ *val = ((guchar *)*val) + sizeof(CORBA_float); ++ break; ++ case CORBA_tk_double: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_double)); ++ DM_GET_ATOM(*val, sizeof(CORBA_double)); ++ *val = ((guchar *)*val) + sizeof(CORBA_double); ++ break; ++ case CORBA_tk_boolean: ++ case CORBA_tk_char: ++ case CORBA_tk_octet: ++ DM_GET_ATOM(*val, sizeof(CORBA_octet)); ++ *val = ((guchar *)*val) + sizeof(CORBA_octet); ++ break; ++ case CORBA_tk_any: ++ { ++ CORBA_any *decoded; ++ ++ *val = ALIGN_ADDRESS(*val, ++ MAX(ALIGNOF_CORBA_LONG, ++ MAX(ALIGNOF_CORBA_POINTER, ALIGNOF_CORBA_STRUCT))); ++ decoded = *val; ++ decoded->_release = CORBA_FALSE; ++ ORBit_demarshal_any(buf, decoded, dup_strings, orb); ++ *val = ((guchar *)*val) + sizeof(CORBA_any); ++ } ++ break; ++ case CORBA_tk_TypeCode: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ ORBit_decode_CORBA_TypeCode(*val, buf); ++ CORBA_Object_duplicate(*(CORBA_Object *)*val, NULL); ++ *val = ((guchar *)*val) + sizeof(CORBA_TypeCode); ++ break; ++ case CORBA_tk_Principal: ++ { ++ CORBA_Principal *p; ++ ++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER))); ++ ++ p = *val; ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long)); ++ CORBA_sequence_set_release(p, dup_strings); ++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long)); ++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1)); ++ memcpy(p->_buffer, buf->cur, p->_length); ++ buf->cur = ((guchar *)buf->cur) + p->_length; ++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet); ++ } ++ break; ++ case CORBA_tk_objref: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ *(CORBA_Object *)*val = ORBit_demarshal_object(buf, orb); ++ *val = ((guchar *)*val) + sizeof(CORBA_Object); ++ break; ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc)); ++ for(i = 0; i < tc->sub_parts; i++) { ++ ORBit_demarshal_value(buf, val, tc->subtypes[i], dup_strings, orb); ++ } ++ break; ++ case CORBA_tk_union: ++ { ++ gpointer discrimptr; ++ ++ discrimptr = *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc)); ++ ORBit_demarshal_value(buf, val, tc->discriminator, dup_strings, orb); ++ n = 1; ++ for(i = 0; i < tc->sub_parts; i++) { ++ n = MAX(n, ORBit_find_alignment(tc->subtypes[i])); ++ } ++ *val = ALIGN_ADDRESS(*val, n); ++ ORBit_demarshal_value(buf, val, ++ ORBit_get_union_tag(tc, &discrimptr, FALSE), ++ dup_strings, orb); ++ } ++ break; ++ case CORBA_tk_string: ++ case CORBA_tk_wstring: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long)); ++ DM_GET_ATOM(&i, sizeof(CORBA_long)); ++ if(dup_strings) ++ *(char **)*val = CORBA_string_dup(buf->cur); ++ else ++ *(char **)*val = buf->cur; ++ *val = ((guchar *)*val) + sizeof(CORBA_char *); ++ buf->cur = (gpointer)((char *)buf->cur + i); ++ break; ++ case CORBA_tk_sequence: ++ { ++ CORBA_sequence_octet *p; ++ gpointer subval; ++ ++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ++ MAX(ALIGNOF_CORBA_LONG, ALIGNOF_CORBA_POINTER))); ++ p = *val; ++ buf->cur = ALIGN_ADDRESS(buf->cur, sizeof(CORBA_long)); ++ DM_GET_ATOM(&p->_length, sizeof(CORBA_long)); ++ if(tc->subtypes[0]->kind == CORBA_tk_octet ++ || tc->subtypes[0]->kind == CORBA_tk_boolean ++ || tc->subtypes[0]->kind == CORBA_tk_char) { ++ /* This special-casing could be taken further to apply to ++ all atoms... */ ++ p->_buffer = ORBit_alloc(p->_length, NULL, GINT_TO_POINTER(1)); ++ memcpy(p->_buffer, buf->cur, p->_length); ++ buf->cur = ((guchar *)buf->cur) + p->_length; ++ } else { ++ p->_buffer = ORBit_demarshal_allocate_mem(tc->subtypes[0], ++ p->_length); ++ subval = p->_buffer; ++ ++ for(i = 0; i < p->_length; i++) ++ ORBit_demarshal_value(buf, &subval, ++ tc->subtypes[0], ++ dup_strings, ++ orb); ++ } ++ ++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet); ++ } ++ break; ++ case CORBA_tk_array: ++ for(i = 0; i < tc->length; i++) ++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb); ++ break; ++ case CORBA_tk_alias: ++ ORBit_demarshal_value(buf, val, tc->subtypes[0], dup_strings, orb); ++ break; ++ case CORBA_tk_fixed: ++ g_error("CORBA_fixed NYI"); ++ break; ++ default: ++ break; ++ } ++} ++ ++gpointer ++ORBit_demarshal_arg(GIOPRecvBuffer *buf, ++ CORBA_TypeCode tc, ++ gboolean dup_strings, ++ CORBA_ORB orb) ++{ ++ gpointer retval, val; ++ ++ retval = val = ORBit_demarshal_allocate_mem(tc, 1); ++ ++ ORBit_demarshal_value(buf, &val, tc, dup_strings, orb); ++ ++ return retval; ++} ++ ++void ++ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval, ++ gboolean dup_strings, ++ CORBA_ORB orb) ++{ ++ gpointer val; ++ ++#if 0 ++ /* I wish I knew whether this was correct or not. It breaks things like 'any anop();' for sure, ++ since we can't always initialize every single possible 'any' underneath _ORBIT_retval */ ++ if(retval->_release) ++ CORBA_free(retval->_value); ++#endif ++ ++ CORBA_any_set_release(retval, CORBA_TRUE); ++ ++ ORBit_decode_CORBA_TypeCode(&retval->_type, buf); ++ CORBA_Object_duplicate((CORBA_Object)retval->_type, NULL); ++ ++ val = retval->_value = ORBit_demarshal_allocate_mem(retval->_type, 1); ++ ORBit_demarshal_value(buf, &val, retval->_type, dup_strings, orb); ++} ++ ++void ++_ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc) ++{ ++ CORBA_long i; ++ gpointer pval1, pval2; ++ ++ switch(tc->kind) { ++ case CORBA_tk_wchar: ++ case CORBA_tk_short: ++ case CORBA_tk_ushort: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_SHORT); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_SHORT); ++ *(CORBA_short *)*newval = *(CORBA_short *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_short); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_short); ++ break; ++ case CORBA_tk_enum: ++ case CORBA_tk_long: ++ case CORBA_tk_ulong: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG); ++ *(CORBA_long *)*newval = *(CORBA_long *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_long); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_long); ++ break; ++ case CORBA_tk_longlong: ++ case CORBA_tk_ulonglong: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_LONG); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_LONG); ++ *(CORBA_long_long *)*newval = *(CORBA_long_long *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_long_long); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_long); ++ break; ++ case CORBA_tk_longdouble: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_LONG_DOUBLE); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_LONG_DOUBLE); ++ *(CORBA_long_double *)*newval = *(CORBA_long_double *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_long_double); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_long_double); ++ break; ++ case CORBA_tk_float: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_FLOAT); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_FLOAT); ++ *(CORBA_long *)*newval = *(CORBA_long *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_float); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_float); ++ break; ++ case CORBA_tk_double: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_DOUBLE); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_DOUBLE); ++ *(CORBA_double *)*newval = *(CORBA_double *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_double); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_double); ++ break; ++ case CORBA_tk_boolean: ++ case CORBA_tk_char: ++ case CORBA_tk_octet: ++ *(CORBA_octet *)*newval = *(CORBA_octet *)*val; ++ *val = ((guchar *)*val) + sizeof(CORBA_octet); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_octet); ++ break; ++ case CORBA_tk_any: ++ { ++ CORBA_any *oldany, *newany; ++ *val = ALIGN_ADDRESS(*val, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER)); ++ *newval = ALIGN_ADDRESS(*newval, MAX(ALIGNOF_CORBA_STRUCT, ALIGNOF_CORBA_POINTER)); ++ oldany = *val; ++ newany = *newval; ++ newany->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)oldany->_type, NULL); ++ /* XXX are we supposed to do this even if oldany->_release ++ == FALSE? */ ++ newany->_value = ORBit_copy_value(oldany->_value, oldany->_type); ++ newany->_release = CORBA_TRUE; ++ *val = ((guchar *)*val) + sizeof(CORBA_any); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_any); ++ } ++ break; ++ case CORBA_tk_Principal: ++ *val = ALIGN_ADDRESS(*val, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ++ ALIGNOF_CORBA_STRUCT), ++ ALIGNOF_CORBA_POINTER)); ++ *newval = ALIGN_ADDRESS(*newval, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ++ ALIGNOF_CORBA_STRUCT), ++ ALIGNOF_CORBA_POINTER)); ++ *(CORBA_Principal *)*newval = *(CORBA_Principal *)*val; ++ ((CORBA_Principal *)*newval)->_buffer = ++ CORBA_octet_allocbuf(((CORBA_Principal *)*newval)->_length); ++ memcpy(((CORBA_Principal *)*newval)->_buffer, ++ ((CORBA_Principal *)*val)->_buffer, ++ ((CORBA_Principal *)*val)->_length); ++ *val = ((guchar *)*val) + sizeof(CORBA_Principal); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_Principal); ++ break; ++ case CORBA_tk_TypeCode: ++ case CORBA_tk_objref: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER); ++ *(CORBA_Object *)*newval = CORBA_Object_duplicate(*(CORBA_Object *)*val, ++ NULL); ++ *val = ((guchar *)*val) + sizeof(CORBA_Object); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_Object); ++ break; ++ case CORBA_tk_struct: ++ case CORBA_tk_except: ++ *val = ALIGN_ADDRESS(*val, ORBit_find_alignment(tc)); ++ *newval = ALIGN_ADDRESS(*newval, ORBit_find_alignment(tc)); ++ for(i = 0; i < tc->sub_parts; i++) { ++ _ORBit_copy_value(val, newval, tc->subtypes[i]); ++ } ++ break; ++ case CORBA_tk_union: ++ { ++ CORBA_TypeCode utc = ORBit_get_union_tag(tc, val, FALSE); ++ gint union_align = ORBit_find_alignment(tc); ++ size_t union_size = ORBit_gather_alloc_info(tc); ++ ++ /* need to advance val,newval by size of union, not just ++ * current tagged field within it */ ++ pval1 = *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_STRUCT); ++ pval2 = *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_STRUCT); ++ _ORBit_copy_value(&pval1, &pval2, tc->discriminator); ++ pval1 = ALIGN_ADDRESS(pval1, union_align); ++ pval2 = ALIGN_ADDRESS(pval2, union_align); ++ _ORBit_copy_value(&pval1, &pval2, utc); ++ *val = ((guchar *)*val) + union_size; ++ *newval = ((guchar *)*newval) + union_size; ++ } ++ break; ++ case CORBA_tk_wstring: ++ case CORBA_tk_string: ++ *val = ALIGN_ADDRESS(*val, ALIGNOF_CORBA_POINTER); ++ *newval = ALIGN_ADDRESS(*newval, ALIGNOF_CORBA_POINTER); ++ ++ *(CORBA_char **)*newval = CORBA_string_dup(*(CORBA_char **)*val); ++ *val = ((guchar *)*val) + sizeof(CORBA_char *); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_char *); ++ break; ++ case CORBA_tk_sequence: ++ *val = ALIGN_ADDRESS(*val, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ++ ALIGNOF_CORBA_STRUCT), ++ ALIGNOF_CORBA_POINTER)); ++ *newval = ALIGN_ADDRESS(*newval, ++ MAX(MAX(ALIGNOF_CORBA_LONG, ++ ALIGNOF_CORBA_STRUCT), ++ ALIGNOF_CORBA_POINTER)); ++ ((CORBA_Principal *)*newval)->_release = CORBA_TRUE; ++ ((CORBA_Principal *)*newval)->_length = ++ ((CORBA_Principal *)*newval)->_maximum = ++ ((CORBA_Principal *)*val)->_length; ++ ((CORBA_Principal *)*newval)->_buffer = pval2 = ++ ORBit_demarshal_allocate_mem(tc->subtypes[0], ++ ((CORBA_Principal *)*val)->_length); ++ pval1 = ((CORBA_Principal *)*val)->_buffer; ++ ++ for(i = 0; i < ((CORBA_Principal *)*newval)->_length; i++) { ++ _ORBit_copy_value(&pval1, &pval2, tc->subtypes[0]); ++ } ++ *val = ((guchar *)*val) + sizeof(CORBA_sequence_octet); ++ *newval = ((guchar *)*newval) + sizeof(CORBA_sequence_octet); ++ break; ++ case CORBA_tk_array: ++ for(i = 0; i < tc->length; i++) { ++ _ORBit_copy_value(val, newval, tc->subtypes[0]); ++ } ++ break; ++ case CORBA_tk_alias: ++ _ORBit_copy_value(val, newval, tc->subtypes[0]); ++ break; ++ case CORBA_tk_fixed: ++ g_error("CORBA_fixed NYI!"); ++ break; ++ case CORBA_tk_void: ++ case CORBA_tk_null: ++ *val = NULL; ++ break; ++ default: ++ g_error("Can't handle copy of value kind %d", tc->kind); ++ } ++} ++ ++gpointer ++ORBit_copy_value(gpointer value, CORBA_TypeCode tc) ++{ ++ gpointer retval, newval; ++ ++ retval = newval = ORBit_demarshal_allocate_mem(tc, 1); ++ _ORBit_copy_value(&value, &newval, tc); ++ ++ return retval; ++} ++ ++void ++CORBA_any__copy(CORBA_any *out, CORBA_any *in) ++{ ++ out->_type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)in->_type, ++ NULL); ++ out->_value = ORBit_copy_value(in->_value, in->_type); ++ out->_release = CORBA_TRUE; ++} +diff -urN linux-2.4.1/net/korbit/orb/corba_any.h linux-2.4.1-korbit/net/korbit/orb/corba_any.h +--- linux-2.4.1/net/korbit/orb/corba_any.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_any.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,45 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ANY_H_ ++#define _ORBIT_CORBA_ANY_H_ ++ ++#include "orbit_types.h" ++#include "corba_typecode.h" ++ ++#include <unistd.h> ++ ++typedef struct CORBA_any_type CORBA_any; ++ ++size_t ORBit_gather_alloc_info(CORBA_TypeCode tc); ++gint ORBit_find_alignment(CORBA_TypeCode tc); ++CORBA_TypeCode ORBit_get_union_tag(CORBA_TypeCode union_tc, ++ gpointer *val, gboolean update); ++gpointer ORBit_copy_value(gpointer value, CORBA_TypeCode tc); ++void _ORBit_copy_value(gpointer *val, gpointer *newval, CORBA_TypeCode tc); ++ ++void CORBA_any__copy(CORBA_any *out, CORBA_any *in); ++ ++#endif /* !_ORBIT_CORBA_ANY_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_any_proto.h linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h +--- linux-2.4.1/net/korbit/orb/corba_any_proto.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_proto.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,16 @@ ++#ifndef _ORBIT_CORBA_ANY_PROTO_H_ ++#define _ORBIT_CORBA_ANY_PROTO_H_ ++ ++void ORBit_marshal_arg(GIOPSendBuffer *buf, ++ gpointer val, ++ CORBA_TypeCode tc); ++void ORBit_marshal_any(GIOPSendBuffer *buf, const CORBA_any *val); ++gpointer ORBit_demarshal_arg(GIOPRecvBuffer *buf, ++ CORBA_TypeCode tc, ++ gboolean dup_strings, ++ CORBA_ORB orb); ++void ORBit_demarshal_any(GIOPRecvBuffer *buf, CORBA_any *retval, ++ gboolean dup_strings, ++ CORBA_ORB orb); ++ ++#endif /* !_ORBIT_CORBA_ANY_PROTO_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_any_type.h linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h +--- linux-2.4.1/net/korbit/orb/corba_any_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_any_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,48 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ANY_TYPE_H_ ++#define _ORBIT_CORBA_ANY_TYPE_H_ ++ ++#include "corba_any.h" ++#include "corba_typecode.h" ++ ++struct CORBA_any_type { ++ CORBA_TypeCode _type; ++ gpointer _value; ++ CORBA_boolean _release; ++}; ++ ++typedef struct ORBit_marshal_value_info_struct { ++ CORBA_TypeCode alias_element_type; ++} ORBit_marshal_value_info; ++ ++#define CORBA_ANYFLAGS_RELEASE 1 ++ ++ ++#endif /* !_ORBIT_CORBA_ANY_TYPE_H_ */ ++ ++ ++ +diff -urN linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h +--- linux-2.4.1/net/korbit/orb/corba_basic_sequences_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_basic_sequences_type.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,43 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_ ++#define _ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_ ++ ++#include <ORBitutil/basic_types.h> ++ ++#ifndef _CORBA_sequence_octet_defined ++#define _CORBA_sequence_octet_defined 1 ++ ++typedef struct CORBA_sequence_octet_struct { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_octet *_buffer; ++ CORBA_boolean _release; ++} CORBA_sequence_octet; ++#endif /* !_CORBA_sequence_octet_defined */ ++ ++#include <orb/corba_sequences.h> ++#endif /* !_ORBIT_CORBA_BASIC_SEQUENCES_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_context.c linux-2.4.1-korbit/net/korbit/orb/corba_context.c +--- linux-2.4.1/net/korbit/orb/corba_context.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.c Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,390 @@ ++#include "orb/orbit.h" ++ ++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); } ++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; } ++ ++static gboolean ++free_entry(gpointer key, gpointer value, gpointer user_data) ++{ ++ g_free(key); ++ g_free(value); ++ ++ return TRUE; ++} ++ ++static void ++ORBit_Context_release(CORBA_Context ctx, CORBA_Environment *ev); ++ ++static gboolean ++free_child(gpointer value, gpointer user_data) ++{ ++ CORBA_Context ctx = value; ++ ++ ORBIT_ROOT_OBJECT(ctx)->refs = 1; ++ ctx->parent_ctx = CORBA_OBJECT_NIL; ++ ORBit_Context_release(ctx, NULL); ++ ++ return TRUE; ++} ++ ++static void ++ORBit_Context_release(CORBA_Context ctx, ++ CORBA_Environment *ev) ++{ ++ ORBIT_ROOT_OBJECT_UNREF(ctx); ++ ++ if(ORBIT_ROOT_OBJECT(ctx)->refs <= 0) { ++ if(ctx->children) { ++ g_slist_foreach(ctx->children, (GFunc)free_child, ctx); ++ g_slist_free(ctx->children); ++ } ++ ++ if(ctx->mappings) { ++ g_hash_table_foreach_remove(ctx->mappings, free_entry, ctx); ++ g_hash_table_destroy(ctx->mappings); ++ } ++ ++ if(ctx->parent_ctx != CORBA_OBJECT_NIL) ++ ctx->parent_ctx->children = g_slist_remove(ctx->parent_ctx->children, ctx->the_name); ++ ++ g_free(ctx->the_name); ++ ++ g_free(ctx); ++ } ++} ++ ++static const ORBit_RootObject_Interface CORBA_Context_epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))ORBit_Context_release, ++}; ++ ++static CORBA_Context ++CORBA_Context_new(CORBA_Context parent, const char *name, CORBA_Environment *ev) ++{ ++ CORBA_Context retval; ++ ++ retval = g_new0(struct CORBA_Context_type, 1); ++ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(retval), ORBIT_PSEUDO_CONTEXT, ev); ++ ++ ORBIT_ROOT_OBJECT(retval)->refs = 0; ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(retval), (gpointer)&CORBA_Context_epv, ev); ++ ++ if(name) ++ retval->the_name = g_strdup(name); ++ ++ retval->parent_ctx = parent; ++ if(parent) ++ parent->children = g_slist_prepend(parent->children, retval); ++ ++ return retval; ++} ++ ++/* Section 5.6.1 */ ++CORBA_Status CORBA_ORB_get_default_context(CORBA_ORB orb, CORBA_Context *ctx, CORBA_Environment *ev) ++{ ++ g_return_if_fail(ev != NULL); ++ o_return_if_fail(orb && ctx); ++ ++ if(!orb->default_ctx) ++ orb->default_ctx = CORBA_Context_new(CORBA_OBJECT_NIL, NULL, ev); ++ ++ *ctx = (CORBA_Context)CORBA_Object_duplicate((CORBA_Object)orb->default_ctx, ev); ++} ++ ++/********* XXX todo - CORBA_Context support */ ++CORBA_Status CORBA_Context_set_one_value(CORBA_Context ctx, CORBA_Identifier prop_name, char *value, CORBA_Environment *ev) ++{ ++ gpointer old_nom, old_value; ++ g_return_if_fail(ev != NULL); ++ o_return_if_fail(ctx && prop_name && value); ++ ++ if(!ctx->mappings) ++ ctx->mappings = g_hash_table_new(g_str_hash, g_str_equal); ++ ++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) { ++ g_free(old_nom); ++ g_free(old_value); ++ } ++ ++ g_hash_table_insert(ctx->mappings, g_strdup(prop_name), g_strdup(value)); ++} ++ ++/* Section 5.6.3 */ ++CORBA_Status CORBA_Context_set_values(CORBA_Context ctx, CORBA_NVList *values, CORBA_Environment *ev) ++{ ++ int i; ++ ++ for(i = 0; i < values->list->len; i++) { ++ CORBA_NamedValue *nvp; ++ ++ nvp = ((CORBA_NamedValue *)values->list->data) + i; ++ ++ g_assert(nvp->argument._type == TC_string); ++ ++ CORBA_Context_set_one_value(ctx, nvp->name, nvp->argument._value, ev); ++ } ++} ++ ++/* Section 5.6.4 */ ++ ++typedef struct { ++ CORBA_Context ctx; ++ CORBA_Identifier prop_name; ++ CORBA_NVList *values; ++ CORBA_Environment *ev; ++ int len; ++} CTXSearchInfo; ++ ++static gboolean ++list_has_key(CORBA_NVList *list, const char *key) ++{ ++ int i; ++ ++ for(i = 0; i < list->list->len; i++) { ++ CORBA_NamedValue *nvp; ++ ++ nvp = ((CORBA_NamedValue *)list->list->data) + i; ++ ++ if(!strcmp(nvp->name, key)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++search_props(gpointer key, gpointer value, CTXSearchInfo *csi) ++{ ++ if(strncmp(key, csi->prop_name, csi->len)) ++ return; ++ ++ if(list_has_key(csi->values, key)) ++ return; ++ ++ CORBA_NVList_add_item(csi->values, key, TC_string, &value, strlen(value) + 1, CORBA_IN_COPY_VALUE, NULL); ++} ++ ++static void ++ctx_get_values(CORBA_Context ctx, CORBA_Flags op_flags, ++ CORBA_Identifier prop_name, CORBA_NVList **values, ++ gint is_wc, ++ CORBA_Environment *ev) ++{ ++ gboolean go_up = FALSE; ++ ++ if(is_wc >= 0) { ++ CTXSearchInfo csi; ++ ++ csi.ctx = ctx; ++ csi.prop_name = prop_name; ++ csi.values = *values; ++ csi.ev = ev; ++ csi.len = is_wc; ++ ++ if(ctx->mappings) ++ g_hash_table_foreach(ctx->mappings, (GHFunc)search_props, &csi); ++ ++ go_up = TRUE; ++ ++ } else { ++ char *val = NULL; ++ ++ if(ctx->mappings) ++ val = g_hash_table_lookup(ctx->mappings, prop_name); ++ ++ if(val) ++ CORBA_NVList_add_item(*values, prop_name, TC_string, &val, strlen(val) + 1, CORBA_IN_COPY_VALUE, ev); ++ else ++ go_up = TRUE; ++ } ++ ++ if(go_up ++ && ctx->parent_ctx ++ && !(op_flags & CORBA_CTX_RESTRICT_SCOPE)) ++ ctx_get_values(ctx->parent_ctx, op_flags, prop_name, values, is_wc, ev); ++} ++ ++CORBA_Status CORBA_Context_get_values(CORBA_Context ctx, ++ CORBA_Identifier start_scope, ++ CORBA_Flags op_flags, ++ CORBA_Identifier prop_name, ++ CORBA_NVList **values, ++ CORBA_Environment *ev) ++{ ++ char *ctmp; ++ int wc_pos; ++ ++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev); ++ ++ if(start_scope && *start_scope) { ++ while(ctx && (!ctx->the_name || strcmp(ctx->the_name, start_scope))) ++ ctx = ctx->parent_ctx; ++ ++ if(!ctx) { ++ CORBA_exception_set_system(ev, ex_CORBA_INV_IDENT, CORBA_COMPLETED_NO); ++ return; ++ } ++ } ++ ++ ctmp = strchr(prop_name, '*'); ++ if(ctmp) ++ wc_pos = ctmp - prop_name; ++ else ++ wc_pos = -1; ++ ++ CORBA_ORB_create_list(CORBA_OBJECT_NIL, 0, values, ev); ++ ++ ctx_get_values(ctx, op_flags, prop_name, values, (prop_name[strlen(prop_name) - 1] == '*'), ev); ++ ++ if((*values)->list->len == 0) ++ { ++ CORBA_NVList_free(*values, ev); ++ *values = NULL; ++ CORBA_exception_set_system(ev, ex_CORBA_UNKNOWN, CORBA_COMPLETED_NO); ++ } ++} ++ ++/* Section 5.6.5 */ ++static void ++delete_props(gpointer key, gpointer value, CTXSearchInfo *csi) ++{ ++ if(strncmp(key, csi->prop_name, csi->len)) ++ return; ++ ++ g_hash_table_remove(csi->ctx->mappings, key); ++ g_free(key); ++ g_free(value); ++} ++ ++CORBA_Status CORBA_Context_delete_values(CORBA_Context ctx, CORBA_Identifier prop_name, CORBA_Environment *ev) ++{ ++ char *ctmp; ++ int wc_pos; ++ ++ if(!ctx->mappings) ++ return; ++ ++ ctmp = strchr(prop_name, '*'); ++ if(ctmp) ++ wc_pos = ctmp - prop_name; ++ else ++ wc_pos = -1; ++ ++ if(wc_pos >= 0) { ++ CTXSearchInfo csi; ++ ++ memset(&csi, 0, sizeof(csi)); ++ csi.ctx = ctx; ++ csi.prop_name = prop_name; ++ csi.ev = ev; ++ csi.len = wc_pos; ++ ++ g_hash_table_foreach(ctx->mappings, (GHFunc)delete_props, &csi); ++ } else { ++ gpointer old_nom, old_value; ++ ++ if(g_hash_table_lookup_extended(ctx->mappings, prop_name, &old_nom, &old_value)) { ++ g_free(old_nom); ++ g_free(old_value); ++ } ++ } ++} ++ ++/* Section 5.6.6 */ ++CORBA_Status CORBA_Context_create_child(CORBA_Context ctx, CORBA_Identifier ctx_name, CORBA_Context *child_ctx, CORBA_Environment *ev) ++{ ++ *child_ctx = CORBA_Context_new(ctx, ctx_name, ev); ++} ++ ++/* Section 5.6.7 */ ++CORBA_Status CORBA_Context_delete(CORBA_Context ctx, CORBA_Flags del_flags, CORBA_Environment *ev) ++{ ++ if((del_flags & CORBA_CTX_DELETE_DESCENDENTS) ++ || !ctx->children) ++ free_child(ctx, NULL); ++} ++ ++void ++ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist, CORBA_unsigned_long nitems, GIOPSendBuffer *buf) ++{ ++ int i; ++ CORBA_unsigned_long *real_nitems, ltmp; ++ ++ real_nitems = giop_send_buffer_append_mem_indirect_a(buf, &nitems, sizeof(nitems)); ++ if(!ctx->mappings) { ++ *real_nitems = 0; ++ return; ++ } ++ ++ for(*real_nitems = i = 0; i < nitems; i++) { ++ char *value; ++ ++ value = g_hash_table_lookup(ctx->mappings, mlist[i].str); ++ if(!value) ++ continue; ++ ++ /* Key */ ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(buf), &(mlist[i].len), sizeof(mlist[i].len)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), mlist[i].str, mlist[i].len); ++ (*real_nitems)++; ++ ++ /* Value */ ++ ltmp = strlen(value) + 1; ++ giop_send_buffer_append_mem_indirect_a(buf, <mp, sizeof(ltmp)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(buf), value, ltmp); ++ (*real_nitems)++; ++ } ++} ++ ++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \ ++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \ ++}G_STMT_END ++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x)) ++ ++void ++ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer) ++{ ++ CORBA_unsigned_long nstrings, keylen, vallen, i; ++ char *key, *value; ++ ++ memset(initme, 0, sizeof(struct CORBA_Context_type)); ++ ORBIT_ROOT_OBJECT(initme)->refs = -1; ++ ++ initme->parent_ctx = parent; ++ ++ ALIGNFOR(nstrings); ++ GET_ATOM(nstrings); ++ ++ if(nstrings) ++ initme->mappings = g_hash_table_new(g_str_hash, g_str_equal); ++ else ++ return; ++ ++ g_hash_table_freeze(initme->mappings); ++ for(i = 0; i < nstrings; ) { ++ ALIGNFOR(keylen); ++ GET_ATOM(keylen); ++ key = recv_buffer->cur; ++ recv_buffer->cur = ((char *)recv_buffer->cur) + keylen; ++ i++; ++ ++ if(i >= nstrings) ++ break; ++ ++ ALIGNFOR(vallen); ++ GET_ATOM(vallen); ++ value = recv_buffer->cur; ++ recv_buffer->cur = ((char *)recv_buffer->cur) + vallen; ++ i++; ++ ++ g_hash_table_insert(initme->mappings, key, value); ++ } ++ g_hash_table_thaw(initme->mappings); ++} ++ ++void ++ORBit_Context_server_free(CORBA_Context ctx) ++{ ++ g_hash_table_destroy(ctx->mappings); ++} +diff -urN linux-2.4.1/net/korbit/orb/corba_context.h linux-2.4.1-korbit/net/korbit/orb/corba_context.h +--- linux-2.4.1/net/korbit/orb/corba_context.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_context.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,65 @@ ++#ifndef CORBA_CONTEXT_H ++#define CORBA_CONTEXT_H 1 ++ ++#include "orbit_object_type.h" ++#include "orbit_object.h" ++ ++typedef struct { ++ CORBA_unsigned_long len; ++ const CORBA_char *str; ++} ORBit_ContextMarshalItem; ++ ++typedef struct CORBA_Context_type *CORBA_Context; ++ ++struct CORBA_Context_type { ++ struct ORBit_PseudoObject_struct parent; ++ GHashTable *mappings; ++ GSList *children; ++ ++ char *the_name; ++ ++ CORBA_Context parent_ctx; ++}; ++ ++ ++extern CORBA_Status CORBA_Context_set_one_value( ++ CORBA_Context ctx, ++ CORBA_Identifier prop_name, ++ char *value, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Context_set_values( ++ CORBA_Context ctx, ++ CORBA_NVList *values, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Context_get_values( ++ CORBA_Context ctx, ++ CORBA_Identifier start_scope, ++ CORBA_Flags op_flags, ++ CORBA_Identifier prop_name, ++ CORBA_NVList **values, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Context_delete_values( ++ CORBA_Context ctx, ++ CORBA_Identifier prop_name, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Context_create_child( ++ CORBA_Context ctx, ++ CORBA_Identifier ctx_name, ++ CORBA_Context *child_ctx, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Context_delete( ++ CORBA_Context ctx, ++ CORBA_Flags del_flags, ++ CORBA_Environment *ev); ++ ++void ORBit_Context_marshal(CORBA_Context ctx, const ORBit_ContextMarshalItem *mlist, ++ CORBA_unsigned_long nitems, GIOPSendBuffer *buf); ++void ORBit_Context_demarshal(CORBA_Context parent, CORBA_Context initme, GIOPRecvBuffer *recv_buffer); ++void ORBit_Context_server_free(CORBA_Context ctx); ++ ++#endif +diff -urN linux-2.4.1/net/korbit/orb/corba_env.h linux-2.4.1-korbit/net/korbit/orb/corba_env.h +--- linux-2.4.1/net/korbit/orb/corba_env.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_env.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,79 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ENV_H_ ++#define _ORBIT_CORBA_ENV_H_ ++ ++typedef struct CORBA_Environment_type CORBA_Environment; ++ ++/* 3.15 */ ++typedef enum { ++ CORBA_COMPLETED_YES=0, ++ CORBA_COMPLETED_NO, ++ CORBA_COMPLETED_MAYBE ++} CORBA_completion_status; ++ ++typedef enum { ++ CORBA_NO_EXCEPTION=0, ++ CORBA_USER_EXCEPTION, ++ CORBA_SYSTEM_EXCEPTION ++} CORBA_exception_type; ++ ++ ++#define ex_CORBA_UNKNOWN 1 ++#define ex_CORBA_BAD_PARAM 2 ++#define ex_CORBA_NO_MEMORY 3 ++#define ex_CORBA_IMP_LIMIT 4 ++#define ex_CORBA_COMM_FAILURE 5 ++#define ex_CORBA_INV_OBJREF 6 ++#define ex_CORBA_NO_PERMISSION 7 ++#define ex_CORBA_INTERNAL 8 ++#define ex_CORBA_MARSHAL 9 ++#define ex_CORBA_INITIALIZE 10 ++#define ex_CORBA_NO_IMPLEMENT 11 ++#define ex_CORBA_BAD_TYPECODE 12 ++#define ex_CORBA_BAD_OPERATION 13 ++#define ex_CORBA_NO_RESOURCES 14 ++#define ex_CORBA_NO_RESPONSE 15 ++#define ex_CORBA_PERSIST_STORE 16 ++#define ex_CORBA_BAD_INV_ORDER 17 ++#define ex_CORBA_TRANSIENT 18 ++#define ex_CORBA_FREE_MEM 19 ++#define ex_CORBA_INV_IDENT 20 ++#define ex_CORBA_INV_FLAG 21 ++#define ex_CORBA_INTF_REPOS 22 ++#define ex_CORBA_BAD_CONTEXT 23 ++#define ex_CORBA_OBJ_ADAPTER 24 ++#define ex_CORBA_DATA_CONVERSION 25 ++#define ex_CORBA_OBJECT_NOT_EXIST 26 ++#define ex_CORBA_TRANSACTION_REQUIRED 27 ++#define ex_CORBA_TRANSACTION_ROLLEDBACK 28 ++#define ex_CORBA_INVALID_TRANSACTION 29 ++ ++ ++#endif /* !_ORBIT_CORBA_ENV_H_ */ ++ ++ ++ +diff -urN linux-2.4.1/net/korbit/orb/corba_env_type.h linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h +--- linux-2.4.1/net/korbit/orb/corba_env_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_env_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,79 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ENV_TYPE_H_ ++#define _ORBIT_CORBA_ENV_TYPE_H_ ++ ++#include "corba_env.h" ++#include "corba_any.h" ++ ++typedef struct CORBA_system_exception { ++ CORBA_unsigned_long minor; ++ CORBA_completion_status completed; ++} CORBA_SystemException; ++ ++#define SYSEXC(name) typedef CORBA_SystemException name; ++ ++SYSEXC(CORBA_UNKNOWN) ++SYSEXC(CORBA_BAD_PARAM) ++SYSEXC(CORBA_NO_MEMORY) ++SYSEXC(CORBA_IMP_LIMIT) ++SYSEXC(CORBA_COMM_FAILURE) ++SYSEXC(CORBA_INV_OBJREF) ++SYSEXC(CORBA_NO_PERMISSION) ++SYSEXC(CORBA_INTERNAL) ++SYSEXC(CORBA_MARSHAL) ++SYSEXC(CORBA_INITIALIZE) ++SYSEXC(CORBA_NO_IMPLEMENT) ++SYSEXC(CORBA_BAD_TYPECODE) ++SYSEXC(CORBA_BAD_OPERATION) ++SYSEXC(CORBA_NO_RESOURCES) ++SYSEXC(CORBA_NO_RESPONSE) ++SYSEXC(CORBA_PERSIST_STORE) ++SYSEXC(CORBA_BAD_INV_ORDER) ++SYSEXC(CORBA_TRANSIENT) ++SYSEXC(CORBA_FREE_MEM) ++SYSEXC(CORBA_INV_IDENT) ++SYSEXC(CORBA_INV_FLAG) ++SYSEXC(CORBA_INTF_REPOS) ++SYSEXC(CORBA_BAD_CONTEXT) ++SYSEXC(CORBA_OBJ_ADAPTER) ++SYSEXC(CORBA_DATA_CONVERSION) ++SYSEXC(CORBA_OBJECT_NOT_EXIST) ++SYSEXC(CORBA_TRANSACTION_REQUIRED) ++SYSEXC(CORBA_TRANSACTION_ROLLEDBACK) ++SYSEXC(CORBA_INVALID_TRANSACTION) ++ ++ ++/* 19.22 */ ++struct CORBA_Environment_type { ++ CORBA_exception_type _major; ++ CORBA_char *_repo_id; ++ void *_params; ++ CORBA_any *_any; ++}; ++ ++ ++#endif /* !_ORBIT_CORBA_ENV_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_object.c linux-2.4.1-korbit/net/korbit/orb/corba_object.c +--- linux-2.4.1/net/korbit/orb/corba_object.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.c Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,467 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++#include "config.h" ++#include <IIOP/IIOP.h> ++#include "orbit_types.h" ++#include "corba_object.h" ++#include "corba_object_type.h" ++#include "env.h" ++#include "orb.h" ++#ifdef __KORBIT__ ++#include "orbit.h" ++#else /* !__KORBIT__ */ ++#include "interface_repository.h" ++#endif /* !__KORBIT__ */ ++#include <signal.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <alloca.h> ++ ++#ifndef __KERNEL__ ++#define freeca(ptr) ++#endif ++ ++#ifndef __KORBIT__ ++/* Section 4.2.1 */ ++CORBA_InterfaceDef CORBA_Object_get_interface(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ CORBA_Repository repo; ++ CORBA_InterfaceDef interface; ++ ++ if(obj==CORBA_OBJECT_NIL) ++ return(CORBA_OBJECT_NIL); /* no exception defined in spec */ ++ ++ repo=CORBA_ORB_resolve_initial_references(obj->orb, "InterfaceRepository", ev); ++ if(repo==CORBA_OBJECT_NIL) ++ return(CORBA_OBJECT_NIL); ++ ++ interface=CORBA_Repository_lookup_id(repo, obj->object_id, ev); ++ CORBA_Object_release(repo, ev); ++ ++ return(interface); ++} ++#endif /* !__KORBIT__ */ ++ ++/* Section 4.2.3 */ ++CORBA_boolean CORBA_Object_is_nil(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ if(obj==CORBA_OBJECT_NIL) { ++ return(CORBA_TRUE); ++ } else { ++ return(CORBA_FALSE); ++ } ++} ++ ++/* Section 4.2.2 */ ++/* XXXX Big warning: lots of places inside ORBit expect this to ++ always return 'obj'. Do not change this, upon pain ++ of death... */ ++CORBA_Object CORBA_Object_duplicate(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ if(obj == CORBA_OBJECT_NIL) ++ return CORBA_OBJECT_NIL; ++ ++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0) ++ ORBIT_ROOT_OBJECT_REF(obj); ++ ++ return(obj); ++} ++ ++ ++/* Section 4.2.2 */ ++void CORBA_Object_release(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ if(obj != CORBA_OBJECT_NIL) ++ ORBIT_ROOT_OBJECT_release(obj,ev); ++} ++ ++extern GHashTable *ORBit_class_assignments; ++ ++void ORBit_impl_CORBA_Object_is_a(gpointer servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment *ev, ++ gpointer dummy) ++{ ++ GIOPSendBuffer *_ORBIT_send_buffer; ++ struct CORBA_Object_struct objdummy; /* XXX badhack to save backwards compat */ ++ CORBA_boolean retval; ++ char *repo_id; ++ CORBA_unsigned_long slen; ++ guchar *curptr; ++ ORBit_ObjectKey *objkey; ++ gpointer *tmp_vepv; ++ guint sz; ++ CORBA_unsigned_long clsid; ++ PortableServer_ServantBase *_ORBIT_servant; ++ ++ _ORBIT_servant = servant; ++ ++ /* XXX security implications */ ++ curptr = _ORBIT_recv_buffer->cur; ++ curptr = ALIGN_ADDRESS(curptr, 4); ++ if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) ++ iiop_byteswap((guchar *)&slen, curptr, sizeof(CORBA_unsigned_long)); ++ else ++ slen = *((CORBA_unsigned_long *)curptr); ++ curptr += 4; ++ repo_id = curptr; ++ ++ repo_id[slen] = '\0'; ++ ++ objkey = ORBIT_OBJECT_KEY(_ORBIT_servant->_private); ++ ++ sz = sizeof(gpointer) * (ORBit_class_assignment_counter + 1); ++ tmp_vepv = alloca(sz); ++ memset(tmp_vepv, '\0', sz); ++ ++ objdummy.vepv = tmp_vepv; ++ objkey->class_info->init_local_objref(&objdummy, servant); ++ ++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, repo_id)); ++ retval = (clsid && tmp_vepv[clsid]); ++ ++ _ORBIT_send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection, NULL, ++ _ORBIT_recv_buffer->message.u.request.request_id, ev->_major); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &retval, sizeof(retval)); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ freeca(tmp_vepv); ++} ++ ++/* Section 4.2.4 */ ++CORBA_boolean CORBA_Object_is_a(CORBA_Object obj, CORBA_char *logical_type_id, CORBA_Environment *ev) ++{ ++ if(obj == CORBA_OBJECT_NIL) ++ return CORBA_FALSE; ++ ++ if (obj->servant && obj->vepv) { ++ CORBA_unsigned_long clsid; ++ ++ clsid = GPOINTER_TO_UINT(g_hash_table_lookup(ORBit_class_assignments, logical_type_id)); ++ ++ return (clsid && (clsid < obj->vepv_size) && obj->vepv[clsid]); ++ } else if(!strcmp(obj->object_id, logical_type_id) ++ || !strcmp("IDL:CORBA/Object:1.0", logical_type_id)) { ++ return CORBA_TRUE; ++ } else { ++ /* Cut and paste from orbit-idl output */ ++ /* XXX security implications */ ++ GIOP_unsigned_long _ORBIT_request_id; ++ register GIOP_unsigned_long _ORBIT_system_exception_minor; ++ register CORBA_completion_status _ORBIT_completion_status; ++ register GIOPSendBuffer *_ORBIT_send_buffer; ++ register GIOPRecvBuffer *_ORBIT_recv_buffer; ++ register GIOPConnection *_cnx; ++ ++ _cnx = ORBit_object_get_connection(obj); ++ ++ _ORBIT_retry_request: ++ _ORBIT_send_buffer = NULL; ++ _ORBIT_recv_buffer = NULL; ++ _ORBIT_completion_status = CORBA_COMPLETED_NO; ++ /* A unique uint pointer is anything on the stack, ++ so set this variable to point to its own address on the ++ stack. :) */ ++ _ORBIT_request_id = GPOINTER_TO_UINT(&_ORBIT_request_id); ++ { /* marshalling */ ++ static const struct { ++ CORBA_unsigned_long len; ++ char opname[6]; ++ } _ORBIT_operation_name_data = { ++ 6, "_is_a" ++ }; ++ static const struct iovec _ORBIT_operation_vec = ++ {(gpointer) & _ORBIT_operation_name_data, 10}; ++ register CORBA_unsigned_long _ORBIT_tmpvar_0; ++ CORBA_unsigned_long _ORBIT_tmpvar_1; ++ ++ _ORBIT_send_buffer = ++ giop_send_request_buffer_use(_cnx, NULL, _ORBIT_request_id, CORBA_TRUE, ++ &(obj->active_profile->object_key_vec), &_ORBIT_operation_vec, &ORBit_default_principal_iovec); ++ ++ _ORBIT_system_exception_minor = ex_CORBA_COMM_FAILURE; ++ if (!_ORBIT_send_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_tmpvar_1 = strlen(logical_type_id) + 1; ++ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), 4); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), &(_ORBIT_tmpvar_1), sizeof(_ORBIT_tmpvar_1)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(_ORBIT_send_buffer), (logical_type_id), sizeof(logical_type_id[_ORBIT_tmpvar_0]) * _ORBIT_tmpvar_1); ++ giop_send_buffer_write(_ORBIT_send_buffer); ++ _ORBIT_completion_status = CORBA_COMPLETED_MAYBE; ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ _ORBIT_send_buffer = NULL; ++ } ++ { /* demarshalling */ ++ register guchar *_ORBIT_curptr; ++ CORBA_boolean _ORBIT_retval; ++ ++ _ORBIT_recv_buffer = giop_recv_reply_buffer_use_2(_cnx, _ORBIT_request_id, TRUE); ++ if (!_ORBIT_recv_buffer) ++ goto _ORBIT_system_exception; ++ _ORBIT_completion_status = CORBA_COMPLETED_YES; ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status != GIOP_NO_EXCEPTION) ++ goto _ORBIT_msg_exception; ++ if (giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer))) { ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr); ++ } else { ++ _ORBIT_curptr = GIOP_RECV_BUFFER(_ORBIT_recv_buffer)->cur; ++ _ORBIT_retval = *((CORBA_boolean *) _ORBIT_curptr); ++ } ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ _ORBIT_system_exception: ++ CORBA_exception_set_system(ev, _ORBIT_system_exception_minor, _ORBIT_completion_status); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ giop_send_buffer_unuse(_ORBIT_send_buffer); ++ return _ORBIT_retval; ++ _ORBIT_msg_exception: ++ if (_ORBIT_recv_buffer->message.u.reply.reply_status == GIOP_LOCATION_FORWARD) { ++ if (obj->forward_locations != NULL) ++ ORBit_delete_profiles(obj->forward_locations); ++ obj->forward_locations = ORBit_demarshal_IOR(_ORBIT_recv_buffer); ++ _cnx = ORBit_object_get_forwarded_connection(obj); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ ++ goto _ORBIT_retry_request; ++ } else { ++ ORBit_handle_exception(_ORBIT_recv_buffer, ev, NULL, obj->orb); ++ giop_recv_buffer_unuse(_ORBIT_recv_buffer); ++ return _ORBIT_retval; ++ } ++ } ++ ++ } ++} ++ ++/* Section 4.2.5 */ ++#ifndef __KORBIT__ ++static void do_exit(int signum) { ++ _exit(5); ++#warning "This should be removed... use BUG instead..." ++} ++#endif ++ ++/* Lovely hack to try and figure out without hanging whether an object exists or not. */ ++CORBA_boolean CORBA_Object_non_existent(CORBA_Object obj, CORBA_Environment *ev) ++{ ++#ifndef __KORBIT__ ++ int childpid, exitstatus, itmp; ++#endif ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ ++ if(obj == CORBA_OBJECT_NIL) ++ return TRUE; ++ ++ if(obj->servant) ++ return FALSE; ++ ++ if(obj->connection && obj->connection->is_valid) ++ return FALSE; ++ ++#ifndef __KORBIT__ ++ childpid = fork(); ++ ++ if(!childpid) { ++ GIOPConnection* cnx = NULL; ++ struct sigaction sa; ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_handler = do_exit; ++ sigaction(SIGALRM, &sa, NULL); ++ alarm(2); ++ cnx = _ORBit_object_get_connection(obj); ++ ++ /* XXX todo - try invoking a strange operation on the object, and see what type of exception we get. */ ++ ++ _exit((cnx == NULL)?1:0); ++ } ++ ++ itmp = waitpid(childpid, &exitstatus, 0); ++ ++ if(itmp < 0) return TRUE; ++ return WEXITSTATUS(exitstatus) && TRUE; ++#else /* __KORBIT__ */ ++ return FALSE; ++#endif /* __KORBIT__ */ ++} ++ ++gboolean ++g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2) ++{ ++ gboolean retval; ++ CORBA_Environment ev; ++ ++ CORBA_exception_init(&ev); ++ ++ retval = (gboolean)CORBA_Object_is_equivalent(obj1, obj2, &ev); ++ ++ CORBA_exception_free(&ev); ++ ++ return retval; ++} ++ ++/* Section 4.2.6 */ ++CORBA_boolean CORBA_Object_is_equivalent(CORBA_Object obj, CORBA_Object other_object, CORBA_Environment *ev) ++{ ++ ORBit_Object_info *obj_profile, *other_object_profile; ++ int i,j, obj_profile_count, other_object_profile_count; ++ ++ if(obj == CORBA_OBJECT_NIL ++ && other_object == CORBA_OBJECT_NIL) ++ return CORBA_TRUE; ++ ++ if(obj == CORBA_OBJECT_NIL ++ || other_object == CORBA_OBJECT_NIL) ++ goto ret_false; ++ ++ /* ++ * If one profile in "obj" matches one in "other_object", then these ++ * objects are equivalent. ++ * ++ * This is O(n*m) at worst case :-( Hopefully though most objects will ++ * only have 1 or 2 profiles. ++ * ++ * The profile list could be indexed as a hash table (the linked list ++ * is still needed, as the profile order is significant) ++ */ ++ ++ obj_profile_count = g_slist_length(obj->profile_list); ++ other_object_profile_count = g_slist_length(other_object->profile_list); ++ ++ for(i=0;i<obj_profile_count;i++) { ++ obj_profile=(ORBit_Object_info *)g_slist_nth_data(obj->profile_list, i); ++ ++ for(j=0;j<other_object_profile_count;j++) { ++ other_object_profile=(ORBit_Object_info *)g_slist_nth_data(other_object->profile_list, j); ++ ++ if(obj_profile->profile_type != other_object_profile->profile_type) ++ continue; ++ ++ if(obj_profile->object_key._length != other_object_profile->object_key._length) ++ continue; ++ ++ if(memcmp(obj_profile->object_key._buffer, other_object_profile->object_key._buffer, obj_profile->object_key._length)) ++ continue; ++ ++ if(obj_profile->profile_type == IOP_TAG_INTERNET_IOP) { ++ TAG_INTERNET_IOP_info *ii1, *ii2; ++ ++ ii1 = &obj_profile->tag.iopinfo; ++ ii2 = &other_object_profile->tag.iopinfo; ++ ++ if(ii1->port != ii2->port) ++ continue; ++ if(strcmp(ii1->host, ii2->host)) ++ continue; ++ ++ return(CORBA_TRUE); ++ } else if(obj_profile->profile_type == IOP_TAG_ORBIT_SPECIFIC) { ++ TAG_ORBIT_SPECIFIC_info *oi1, *oi2; ++ ++ oi1 = &obj_profile->tag.orbitinfo; ++ oi2 = &other_object_profile->tag.orbitinfo; ++ ++ if(strcmp(oi1->unix_sock_path, oi2->unix_sock_path)) ++ continue; ++ if(oi1->ipv6_port != oi2->ipv6_port) ++ continue; ++ ++ return(CORBA_TRUE); ++ } ++ } ++ } ++ ++ ret_false: ++ return CORBA_FALSE; ++} ++ ++guint ++g_CORBA_Object_hash(CORBA_Object obj) ++{ ++ guint retval; ++ CORBA_Environment ev; ++ ++ CORBA_exception_init(&ev); ++ ++ retval = (guint)CORBA_Object_hash(obj, UINT_MAX, &ev); ++ ++ CORBA_exception_free(&ev); ++ ++ return retval; ++} ++ ++static void profile_hash(gpointer item, gpointer data) ++{ ++ ORBit_Object_info *info = (ORBit_Object_info *)item; ++ CORBA_unsigned_long *retval = (CORBA_unsigned_long *)data; ++ ++ g_assert(info); ++ g_assert(retval); ++ ++ *retval ^= info->object_key._length; ++ ++ if(info->profile_type == IOP_TAG_INTERNET_IOP) { ++ *retval ^= !info->tag.iopinfo.port; ++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { ++ *retval ^= g_str_hash(info->tag.orbitinfo.unix_sock_path); ++ *retval ^= !info->tag.orbitinfo.ipv6_port; ++ } ++} ++ ++/* Section 4.2.6 */ ++CORBA_unsigned_long CORBA_Object_hash(CORBA_Object obj, ++ CORBA_unsigned_long maximum, ++ CORBA_Environment *ev) ++{ ++ CORBA_unsigned_long retval = 0; ++ char *tptr; ++ ++ g_assert(obj); ++ ++ tptr = obj->object_id; ++ while(*tptr) { ++ retval = (retval << 8) ^ *tptr; ++ tptr++; ++ } ++ ++ if(g_slist_length(obj->profile_list)>0) { ++ g_slist_foreach(obj->profile_list, profile_hash, &retval); ++ } else { ++ g_warning("Object of type %s doesn't seem to have any connection info!", obj->object_id); ++ } ++ ++ return (retval % maximum); ++} ++ ++/* Section 4.2.7 */ ++CORBA_Policy CORBA_Object_get_policy(CORBA_Object obj, CORBA_PolicyType policy_type, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} +diff -urN linux-2.4.1/net/korbit/orb/corba_object.h linux-2.4.1-korbit/net/korbit/orb/corba_object.h +--- linux-2.4.1/net/korbit/orb/corba_object.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_object.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,59 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_OBJECT_H_ ++#define _ORBIT_CORBA_OBJECT_H_ ++ ++#include <ORBitutil/basic_types.h> ++ ++#include "corba_env.h" ++#include "corba_orb.h" ++#include "corba_sequences.h" ++ ++#define CORBA_OBJECT_NIL NULL ++ ++typedef struct CORBA_Object_struct *CORBA_Object; ++ ++#define CORBA_OBJECT(x) ((CORBA_Object)(x)) ++ ++/* Used for internal stuff mostly, but also good if you want to store ++ a hash of objects */ ++gboolean g_CORBA_Object_equal(CORBA_Object obj1, CORBA_Object obj2); ++guint g_CORBA_Object_hash(CORBA_Object obj); ++ ++void ORBit_impl_CORBA_Object_is_a(gpointer servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ CORBA_Environment *ev, gpointer dummy); ++#define ORBIT_IMPLEMENTS_IS_A ++ ++extern CORBA_boolean CORBA_Object_is_a( ++ CORBA_Object obj, ++ CORBA_char *logical_type_id, ++ CORBA_Environment *ev); ++ ++#endif /* !_ORBIT_CORBA_OBJECT_H_ */ ++ ++ ++ +diff -urN linux-2.4.1/net/korbit/orb/corba_object_type.h linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h +--- linux-2.4.1/net/korbit/orb/corba_object_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_object_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,54 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_OBJECT_TYPE_H_ ++#define _ORBIT_CORBA_OBJECT_TYPE_H_ ++ ++#include <sys/uio.h> /* for struct iovec */ ++ ++#include <IIOP/IIOP.h> /* for giop_connection */ ++ ++#include "corba_object.h" ++#include "corba_basic_sequences_type.h" ++ ++#include "orbit_object_type.h" ++ ++struct CORBA_Object_struct { ++ struct ORBit_RootObject_struct parent; ++ CORBA_ORB orb; ++ GIOPConnection *connection; ++ CORBA_char *object_id; ++ GSList *profile_list; ++ GSList *forward_locations; ++ ORBit_Object_info *active_profile; /* points at a member of profile_list or forward_locations */ ++ ++ /* Used for direct calls */ ++ gpointer *vepv; ++ /* PortableServer_Servant - looping includes :( */ gpointer servant; ++ guint vepv_size; ++}; ++ ++ ++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_orb.h linux-2.4.1-korbit/net/korbit/orb/corba_orb.h +--- linux-2.4.1/net/korbit/orb/corba_orb.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,48 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ORB_H_ ++#define _ORBIT_CORBA_ORB_H_ ++ ++typedef char *CORBA_ORB_ObjectId; ++ ++#ifndef CORBA_POLICY_TYPE ++#define CORBA_POLICY_TYPE 1 ++/* We need to define this in corba_orb_type.h as well, sometimes... */ ++typedef struct CORBA_Policy_type *CORBA_Policy; ++#endif ++ ++typedef CORBA_unsigned_long CORBA_PolicyType; ++ ++typedef struct CORBA_ORB_type *CORBA_ORB; ++ ++typedef struct CORBA_DomainManager_type *CORBA_DomainManager; ++ ++typedef struct CORBA_ConstructionPolicy_type *CORBA_ConstructionPolicy; ++ ++#define ex_CORBA_ORB_InvalidName "IDL:CORBA/ORB/InvalidName:1.0" ++ ++#endif /* !_ORBIT_CORBA_ORB_H_ */ ++ +diff -urN linux-2.4.1/net/korbit/orb/corba_orb_type.h linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h +--- linux-2.4.1/net/korbit/orb/corba_orb_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_orb_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,77 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_ORB_TYPE_H_ ++#define _ORBIT_CORBA_ORB_TYPE_H_ ++ ++#include "corba_object.h" ++ ++struct CORBA_ORB_type { ++ struct ORBit_PseudoObject_struct parent; ++ CORBA_ORBid orb_identifier; ++ CORBA_RepositoryId repoid; ++ CORBA_boolean use_poa; ++ ++ CORBA_Object imr, ir, naming, root_poa; ++ struct { ++ GIOPConnection *ipv4; ++ GIOPConnection *ipv6; ++ GIOPConnection *usock; ++ } cnx; ++ ++ GHashTable *objrefs; ++ ++ GPtrArray *poas; ++ ++ CORBA_Context default_ctx; ++}; ++ ++#define CORBA_ORB_CAST(orb) ((CORBA_ORB)orb) ++ ++typedef struct CORBA_ORB_InvalidName { ++ int dummy; ++} CORBA_ORB_InvalidName; ++ ++struct CORBA_Policy_type { ++ struct ORBit_PseudoObject_struct parent; ++ CORBA_PolicyType policy_type; ++}; ++#ifndef CORBA_POLICY_TYPE ++#define CORBA_POLICY_TYPE 1 ++typedef struct CORBA_Policy_type *CORBA_Policy; ++#endif ++ ++struct CORBA_DomainManager_type { ++ struct ORBit_PseudoObject_struct parent; ++}; ++ ++#define CORBA_SecConstruction (11) ++ ++struct CORBA_ConstructionPolicy_type { ++ int fill_me_in; ++}; ++ ++ ++#endif /* !_ORBIT_CORBA_ORB_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h +--- linux-2.4.1/net/korbit/orb/corba_portableserver.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,80 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_PORTABLESERVER_H_ ++#define _ORBIT_CORBA_PORTABLESERVER_H_ ++ ++typedef struct PortableServer_ThreadPolicy_type *PortableServer_ThreadPolicy; ++typedef struct PortableServer_LifespanPolicy_type *PortableServer_LifespanPolicy; ++typedef struct PortableServer_IdUniquenessPolicy_type *PortableServer_IdUniquenessPolicy; ++typedef struct PortableServer_IdAssignmentPolicy_type *PortableServer_IdAssignmentPolicy; ++typedef struct PortableServer_ImplicitActivationPolicy_type *PortableServer_ImplicitActivationPolicy; ++typedef struct PortableServer_ServantRetentionPolicy_type *PortableServer_ServantRetentionPolicy; ++typedef struct PortableServer_RequestProcessingPolicy_type *PortableServer_RequestProcessingPolicy; ++typedef struct PortableServer_POAManager_type* PortableServer_POAManager; ++typedef struct PortableServer_AdapterActivator_type *PortableServer_AdapterActivator; ++typedef struct PortableServer_ServantManager_type *PortableServer_ServantManager; ++typedef struct PortableServer_ServantActivator_type *PortableServer_ServantActivator; ++typedef struct PortableServer_ServantLocator_type *PortableServer_ServantLocator; ++typedef struct PortableServer_POA_type *PortableServer_POA; ++typedef struct PortableServer_Current_type *PortableServer_Current; ++ ++typedef enum { ++ PortableServer_ORB_CTRL_MODEL=0, ++ PortableServer_SINGLE_THREAD_MODEL ++} PortableServer_ThreadPolicyValue; ++ ++typedef enum { ++ PortableServer_TRANSIENT=0, ++ PortableServer_PERSISTENT ++} PortableServer_LifespanPolicyValue; ++ ++typedef enum { ++ PortableServer_UNIQUE_ID=0, ++ PortableServer_MULTIPLE_ID ++} PortableServer_IdUniquenessPolicyValue; ++ ++typedef enum { ++ PortableServer_USER_ID=0, ++ PortableServer_SYSTEM_ID ++} PortableServer_IdAssignmentPolicyValue; ++ ++typedef enum { ++ PortableServer_IMPLICIT_ACTIVATION=0, ++ PortableServer_NO_IMPLICIT_ACTIVATION ++} PortableServer_ImplicitActivationPolicyValue; ++ ++typedef enum { ++ PortableServer_RETAIN=0, ++ PortableServer_NON_RETAIN ++} PortableServer_ServantRetentionPolicyValue; ++ ++typedef enum { ++ PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY=0, ++ PortableServer_USE_DEFAULT_SERVANT, ++ PortableServer_USE_SERVANT_MANAGER ++} PortableServer_RequestProcessingPolicyValue; ++ ++#endif /* !_ORBIT_CORBA_PORTABLESERVER_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_portableserver_type.h linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h +--- linux-2.4.1/net/korbit/orb/corba_portableserver_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_portableserver_type.h Thu Feb 1 11:47:11 2001 +@@ -0,0 +1,361 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_PORTABLESERVER_TYPE_H_ ++#define _ORBIT_CORBA_PORTABLESERVER_TYPE_H_ ++ ++/* 19.26 */ ++ ++typedef void *PortableServer_ServantLocator_Cookie; ++typedef void *PortableServer_Servant; ++ ++#ifndef _PortableServer_ForwardRequest_defined ++#define _PortableServer_ForwardRequest_defined ++ ++typedef struct PortableServer_ForwardRequest { ++ CORBA_Object forward_reference; ++} PortableServer_ForwardRequest; ++ ++#define ex_PortableServer_ForwardRequest "IDL:PortableServer/ForwardRequest:1.0" ++#endif /* !_PortableServer_ForwardRequest_defined */ ++ ++#define PortableServer_THREAD_POLICY_ID 16 ++struct PortableServer_ThreadPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_ThreadPolicyValue value; ++}; ++ ++#define PortableServer_LIFESPAN_POLICY_ID 17 ++extern const CORBA_PolicyType PortableServer_LifespanPolicy_PolicyType; ++struct PortableServer_LifespanPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_LifespanPolicyValue value; ++}; ++ ++#define PortableServer_ID_UNIQUENESS_POLICY_ID 18 ++struct PortableServer_IdUniquenessPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_IdUniquenessPolicyValue value; ++}; ++ ++#define PortableServer_ID_ASSIGNMENT_POLICY_ID 19 ++struct PortableServer_IdAssignmentPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_IdAssignmentPolicyValue value; ++}; ++ ++#define PortableServer_IMPLICIT_ACTIVATION_POLICY_ID 20 ++struct PortableServer_ImplicitActivationPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_ImplicitActivationPolicyValue value; ++}; ++ ++#define PortableServer_SERVANT_RETENTION_POLICY_ID 21 ++struct PortableServer_ServantRetentionPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_ServantRetentionPolicyValue value; ++}; ++ ++#define PortableServer_REQUEST_PROCESSING_POLICY_ID 22 ++struct PortableServer_RequestProcessingPolicy_type { ++ struct CORBA_Policy_type corba_policy; ++ PortableServer_RequestProcessingPolicyValue value; ++}; ++ ++#ifndef _PortableServer_POAManager_AdapterInactive_defined ++#define _PortableServer_POAManager_AdapterInactive_defined ++ ++typedef struct PortableServer_POAManager_AdapterInactive { ++ int fill_me_in; ++} PortableServer_POAManager_AdapterInactive; ++ ++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0" ++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */ ++ ++typedef enum { PortableServer_POAManager_HOLDING, ++ PortableServer_POAManager_ACTIVE, ++ PortableServer_POAManager_DISCARDING, ++ PortableServer_POAManager_INACTIVE ++} PortableServer_POAManager_State; ++ ++struct PortableServer_POAManager_type { ++ struct ORBit_PseudoObject_struct parent; ++ GSList* poa_collection; ++ CORBA_ORB orb; ++ PortableServer_POAManager_State state; ++}; ++ ++struct PortableServer_AdapterActivator_type { ++ int fill_me_in; ++}; ++ ++struct PortableServer_ServantManager_type { ++ int fill_me_in; ++}; ++ ++#ifndef _PortableServer_POA_AdapterAlreadyExists_defined ++#define _PortableServer_POA_AdapterAlreadyExists_defined ++ ++typedef struct PortableServer_POA_AdapterAlreadyExists { ++ int fill_me_in; ++} PortableServer_POA_AdapterAlreadyExists; ++ ++#define ex_PortableServer_POA_AdapterAlreadyExists "IDL:PortableServer/POA/AdapterAlreadyExists:1.0" ++#endif /* !_PortableServer_POA_AdapterAlreadyExists_defined */ ++ ++#ifndef _PortableServer_POAManager_AdapterInactive_defined ++#define _PortableServer_POAManager_AdapterInactive_defined ++ ++typedef struct PortableServer_POAManager_AdapterInactive { ++ int fill_me_in; ++} PortableServer_POAManager_AdapterInactive; ++ ++#define ex_PortableServer_POAManager_AdapterInactive "IDL:PortableServer/POAManager/AdapterInactive:1.0" ++#endif /* !_PortableServer_POAManager_AdapterInactive_defined */ ++ ++#ifndef _PortableServer_POA_AdapterNonExistent_defined ++#define _PortableServer_POA_AdapterNonExistent_defined ++ ++typedef struct PortableServer_POA_AdapterNonExistent { ++ int fill_me_in; ++} PortableServer_POA_AdapterNonExistent; ++ ++#define ex_PortableServer_POA_AdapterNonExistent "IDL:PortableServer/POA/AdapterNonExistent:1.0" ++#endif /* !_PortableServer_POA_AdapterNonExistent_defined */ ++ ++#ifndef _PortableServer_POA_InvalidPolicy_defined ++#define _PortableServer_POA_InvalidPolicy_defined ++ ++typedef struct PortableServer_POA_InvalidPolicy { ++ CORBA_unsigned_short index; ++} PortableServer_POA_InvalidPolicy; ++ ++#define ex_PortableServer_POA_InvalidPolicy "IDL:PortableServer/POA/InvalidPolicy:1.0" ++#endif /* !_PortableServer_POA_InvalidPolicy_defined */ ++ ++#ifndef _PortableServer_POA_NoServant_defined ++#define _PortableServer_POA_NoServant_defined ++ ++typedef struct PortableServer_POA_NoServant { ++ int fill_me_in; ++} PortableServer_POA_NoServant; ++ ++#define ex_PortableServer_POA_NoServant "IDL:PortableServer/POA/NoServant:1.0" ++#endif /* !_PortableServer_POA_NoServant_defined */ ++ ++#ifndef _PortableServer_POA_ObjectAlreadyActive_defined ++#define _PortableServer_POA_ObjectAlreadyActive_defined ++ ++typedef struct PortableServer_POA_ObjectAlreadyActive { ++ int fill_me_in; ++} PortableServer_POA_ObjectAlreadyActive; ++ ++#define ex_PortableServer_POA_ObjectAlreadyActive "IDL:PortableServer/POA/ObjectAlreadyActive:1.0" ++#endif /* !_PortableServer_POA_ObjectAlreadyActive_defined */ ++ ++#ifndef _PortableServer_POA_ObjectNotActive_defined ++#define _PortableServer_POA_ObjectNotActive_defined ++ ++typedef struct PortableServer_POA_ObjectNotActive { ++ int fill_me_in; ++} PortableServer_POA_ObjectNotActive; ++ ++#define ex_PortableServer_POA_ObjectNotActive "IDL:PortableServer/POA/ObjectNotActive:1.0" ++#endif /* !_PortableServer_POA_ObjectNotActive_defined */ ++ ++#ifndef _PortableServer_POA_ServantAlreadyActive_defined ++#define _PortableServer_POA_ServantAlreadyActive_defined ++ ++typedef struct PortableServer_POA_ServantAlreadyActive { ++ int fill_me_in; ++} PortableServer_POA_ServantAlreadyActive; ++ ++#define ex_PortableServer_POA_ServantAlreadyActive "IDL:PortableServer/POA/ServantAlreadyActive:1.0" ++#endif /* !_PortableServer_POA_ServantAlreadyActive_defined */ ++ ++#ifndef _PortableServer_POA_ServantNotActive_defined ++#define _PortableServer_POA_ServantNotActive_defined ++ ++typedef struct PortableServer_POA_ServantNotActive { ++ int fill_me_in; ++} PortableServer_POA_ServantNotActive; ++ ++#define ex_PortableServer_POA_ServantNotActive "IDL:PortableServer/POA/ServantNotActive:1.0" ++#endif /* !_PortableServer_POA_ServantNotActive_defined */ ++ ++#ifndef _PortableServer_POA_WrongAdapter_defined ++#define _PortableServer_POA_WrongAdapter_defined ++ ++typedef struct PortableServer_POA_WrongAdapter { ++ int fill_me_in; ++} PortableServer_POA_WrongAdapter; ++ ++#define ex_PortableServer_POA_WrongAdapter "IDL:PortableServer/POA/WrongAdapter:1.0" ++#endif /* !_PortableServer_POA_WrongAdapter_defined */ ++ ++#ifndef _PortableServer_POA_WrongPolicy_defined ++#define _PortableServer_POA_WrongPolicy_defined ++ ++typedef struct PortableServer_POA_WrongPolicy { ++ int fill_me_in; ++} PortableServer_POA_WrongPolicy; ++ ++#define ex_PortableServer_POA_WrongPolicy "IDL:PortableServer/POA/WrongPolicy:1.0" ++#endif /* !_PortableServer_POA_WrongPolicy_defined */ ++ ++#ifndef _PortableServer_Current_NoContext_defined ++#define _PortableServer_Current_NoContext_defined ++ ++typedef struct PortableServer_Current_NoContext { ++ int fill_me_in; ++} PortableServer_Current_NoContext; ++ ++#define ex_PortableServer_Current_NoContext "IDL:PortableServer/Current/NoContext:1.0" ++#endif /* !_PortableServer_Current_NoContext_defined */ ++ ++struct PortableServer_Current_type { ++ int fill_me_in; ++}; ++ ++typedef struct PortableServer_ServantBase__epv { ++ void *_private; ++ void (*finalize)(PortableServer_Servant, CORBA_Environment *); ++ PortableServer_POA (*default_POA)(PortableServer_Servant, CORBA_Environment *); ++} PortableServer_ServantBase__epv; ++ ++typedef PortableServer_ServantBase__epv *PortableServer_ServantBase__vepv; ++ ++typedef struct PortableServer_ServantBase { ++ void *_private; ++ PortableServer_ServantBase__vepv *vepv; ++} PortableServer_ServantBase; ++ ++/* 19.27 */ ++ ++typedef void (*PortableServer_DynamicImplRoutine) (PortableServer_Servant servant, CORBA_ServerRequest request); ++ ++typedef struct PortableServer_DynamicImpl__epv { ++ void *_private; ++ PortableServer_DynamicImplRoutine invoke; ++ CORBA_RepositoryId (*primary_interface) (PortableServer_Servant svt, PortableServer_ObjectId id, PortableServer_POA poa, CORBA_Environment *env); ++} PortableServer_DynamicImpl__epv; ++ ++typedef struct PortableServer_DynamicImpl__vepv { ++ PortableServer_ServantBase__epv *_base_epv; ++ PortableServer_DynamicImpl__epv *PortableServer_DynamicImpl_epv; ++} PortableServer_DynamicImpl__vepv; ++ ++typedef struct PortableServer_DynamicImpl { ++ void *_private; ++ PortableServer_DynamicImpl__vepv *vepv; ++} PortableServer_DynamicImpl; ++ ++typedef struct { ++ void *_private; ++} POA_PortableServer_ServantManager__epv; ++ ++typedef struct { ++ void *_private; ++ ++ PortableServer_Servant (*incarnate) (PortableServer_Servant servant, ++ PortableServer_ObjectId * oid, ++ PortableServer_POA adapter, ++ CORBA_Environment * ev); ++ ++ void (*etherealize) (PortableServer_Servant servant, ++ PortableServer_ObjectId* oid, ++ PortableServer_POA adapter, ++ PortableServer_Servant serv, ++ CORBA_boolean cleanup_in_progress, ++ CORBA_boolean remaining_activations, ++ CORBA_Environment * ev); ++ ++} POA_PortableServer_ServantActivator__epv; ++ ++typedef struct { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv; ++ POA_PortableServer_ServantActivator__epv *PortableServer_ServantActivator_epv; ++} POA_PortableServer_ServantActivator__vepv; ++ ++typedef struct { ++ void *_private; ++ POA_PortableServer_ServantActivator__vepv *vepv; ++} POA_PortableServer_ServantActivator; ++ ++extern void ++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++extern void ++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ ++typedef struct { ++ void *_private; ++ ++ PortableServer_Servant (*preinvoke) (PortableServer_Servant servant, ++ PortableServer_ObjectId * oid, ++ PortableServer_POA adapter, ++ CORBA_Identifier operation, ++ PortableServer_ServantLocator_Cookie *the_cookie, ++ CORBA_Environment * ev); ++ ++ void (*postinvoke) (PortableServer_Servant servant, ++ PortableServer_ObjectId * oid, ++ PortableServer_POA adapter, ++ CORBA_Identifier operation, ++ PortableServer_ServantLocator_Cookie the_cookie, ++ PortableServer_Servant the_servant, ++ CORBA_Environment * ev); ++} POA_PortableServer_ServantLocator__epv; ++ ++typedef struct { ++ PortableServer_ServantBase__epv *_base_epv; ++ POA_PortableServer_ServantManager__epv *PortableServer_ServantManager_epv; ++ POA_PortableServer_ServantLocator__epv *PortableServer_ServantLocator_epv; ++} POA_PortableServer_ServantLocator__vepv; ++ ++typedef struct { ++ void *_private; ++ POA_PortableServer_ServantLocator__vepv *vepv; ++} POA_PortableServer_ServantLocator; ++ ++extern void ++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++extern void ++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev); ++ ++struct CORBA_ServerRequest_type { ++ struct ORBit_PseudoObject_struct parent; ++ GIOPRecvBuffer *rbuf; ++ GIOPSendBuffer *sbuf; ++ CORBA_NVList *params; ++ CORBA_ORB orb; ++ guchar did_ctx, did_exc; ++}; ++ ++#endif /* !_ORBIT_CORBA_PORTABLESERVER_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_sequences.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h +--- linux-2.4.1/net/korbit/orb/corba_sequences.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,74 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_SEQUENCES_H_ ++#define _ORBIT_CORBA_SEQUENCES_H_ ++ ++ ++/* moved from sequences.h */ ++#include "corba_basic_sequences_type.h" ++ ++typedef CORBA_sequence_octet CORBA_ReferenceData; ++ ++#define _CORBA_sequence_ServiceOption_defined ++typedef struct CORBA_sequence_ServiceOption CORBA_sequence_ServiceOption; ++ ++#define _CORBA_sequence_ServiceDetail_defined ++typedef struct CORBA_sequence_ServiceDetail CORBA_sequence_ServiceDetail; ++ ++#define _CORBA_sequence_ORB_ObjectId_defined ++typedef struct CORBA_sequence_ORB_ObjectId CORBA_ORB_ObjectIdList; ++ ++#define _CORBA_sequence_NameValuePair_defined ++typedef struct CORBA_sequence_NameValuePair CORBA_NameValuePairSeq; ++ ++#define _CORBA_sequence_CORBA_any_defined ++typedef struct CORBA_sequence_CORBA_any_struct CORBA_AnySeq; ++typedef struct CORBA_sequence_CORBA_any_struct CORBA_sequence_CORBA_any; ++ ++#define _CORBA_sequence_Policy_defined ++typedef struct CORBA_sequence_Policy CORBA_PolicyList; ++ ++#define _CORBA_sequence_DomainManager_defined ++typedef struct CORBA_sequence_DomainManager CORBA_DomainManagerList; ++ ++#define _PortableServer_sequence_octet_defined ++typedef struct PortableServer_sequence_octet PortableServer_ObjectId; ++ ++ ++/* Moved from orbit_types.h */ ++#ifndef HAVE_CORBA_PRINCIPAL ++#define HAVE_CORBA_PRINCIPAL 1 ++typedef CORBA_sequence_octet CORBA_Principal; ++#endif ++typedef CORBA_sequence_octet CORBA_DynAny_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynFixed_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynEnum_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynStruct_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynUnion_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynSequence_OctetSeq; ++typedef CORBA_sequence_octet CORBA_DynArray_OctetSeq; ++ ++#endif /* !_ORBIT_CORBA_SEQUENCES_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_sequences_type.h linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h +--- linux-2.4.1/net/korbit/orb/corba_sequences_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_sequences_type.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,98 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_SEQUENCES_TYPE_H_ ++#define _ORBIT_CORBA_SEQUENCES_TYPE_H_ ++ ++#include "corba_sequences.h" ++ ++struct CORBA_sequence_ServiceOption { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_ServiceOption *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_ServiceDetail { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_ServiceDetail *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_ORB_ObjectId { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_ORB_ObjectId *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_NameValuePair { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ struct CORBA_NameValuePair *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_CORBA_any_struct { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_any *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_Policy { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_Policy *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct CORBA_sequence_DomainManager { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_DomainManager *_buffer; ++ CORBA_boolean _release; ++}; ++ ++struct PortableServer_sequence_octet { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CORBA_octet *_buffer; ++ CORBA_boolean _release; ++}; ++ ++/* Generic sequence */ ++struct CORBA_Sequence_type { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ void *_buffer; ++ CORBA_boolean _release; ++}; ++ ++#define CORBA_SEQFLAGS_RELEASE 1 ++ ++ ++#endif /* !_ORBIT_CORBA_SEQUENCES_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/corba_typecode.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h +--- linux-2.4.1/net/korbit/orb/corba_typecode.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,167 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_TYPECODE_H_ ++#define _ORBIT_CORBA_TYPECODE_H_ ++ ++/* moved from orbit_types.h */ ++typedef struct CORBA_TypeCode_struct *CORBA_TypeCode; ++ ++typedef enum { ++ CORBA_tk_null=0, ++ CORBA_tk_void=1, ++ CORBA_tk_short=2, ++ CORBA_tk_long=3, ++ CORBA_tk_ushort=4, ++ CORBA_tk_ulong=5, ++ CORBA_tk_float=6, ++ CORBA_tk_double=7, ++ CORBA_tk_boolean=8, ++ CORBA_tk_char=9, ++ CORBA_tk_octet=10, ++ CORBA_tk_any=11, ++ CORBA_tk_TypeCode=12, ++ CORBA_tk_Principal=13, ++ CORBA_tk_objref=14, ++ CORBA_tk_struct=15, ++ CORBA_tk_union=16, ++ CORBA_tk_enum=17, ++ CORBA_tk_string=18, ++ CORBA_tk_sequence=19, ++ CORBA_tk_array=20, ++ CORBA_tk_alias=21, ++ CORBA_tk_except=22, ++ CORBA_tk_longlong=23, ++ CORBA_tk_ulonglong=24, ++ CORBA_tk_longdouble=25, ++ CORBA_tk_wchar=26, ++ CORBA_tk_wstring=27, ++ CORBA_tk_fixed=28, ++ CORBA_tk_recursive=0xffffffff, ++ CORBA_tk_last=29 /* hack for GIOP */ ++} CORBA_TCKind; ++ ++#define TC_CORBA_short TC_short ++#define TC_CORBA_long TC_long ++#define TC_CORBA_longlong TC_longlong ++#define TC_CORBA_long_long TC_longlong ++#define TC_CORBA_ushort TC_ushort ++#define TC_CORBA_unsigned_short TC_ushort ++#define TC_CORBA_ulong TC_ulong ++#define TC_CORBA_unsigned_long TC_ulong ++#define TC_CORBA_ulonglong TC_ulonglong ++#define TC_CORBA_unsigned_long_long TC_ulonglong ++#define TC_CORBA_float TC_float ++#define TC_CORBA_double TC_double ++#define TC_CORBA_longdouble TC_longdouble ++#define TC_CORBA_long_double TC_longdouble ++#define TC_CORBA_boolean TC_boolean ++#define TC_CORBA_char TC_char ++#define TC_CORBA_wchar TC_wchar ++#define TC_CORBA_octet TC_octet ++#define TC_CORBA_any TC_any ++#define TC_CORBA_TypeCode TC_TypeCode ++#define TC_CORBA_Principal TC_Principal ++#define TC_CORBA_Object TC_Object ++#define TC_CORBA_string TC_string ++#define TC_CORBA_wstring TC_wstring ++ ++#define TC_null ((CORBA_TypeCode)&TC_null_struct) ++#define TC_void ((CORBA_TypeCode)&TC_void_struct) ++#define TC_short ((CORBA_TypeCode)&TC_short_struct) ++#define TC_long ((CORBA_TypeCode)&TC_long_struct) ++#define TC_longlong ((CORBA_TypeCode)&TC_longlong_struct) ++#define TC_ushort ((CORBA_TypeCode)&TC_ushort_struct) ++#define TC_ulong ((CORBA_TypeCode)&TC_ulong_struct) ++#define TC_ulonglong ((CORBA_TypeCode)&TC_ulonglong_struct) ++#define TC_float ((CORBA_TypeCode)&TC_float_struct) ++#define TC_double ((CORBA_TypeCode)&TC_double_struct) ++#define TC_longdouble ((CORBA_TypeCode)&TC_longdouble_struct) ++#define TC_boolean ((CORBA_TypeCode)&TC_boolean_struct) ++#define TC_char ((CORBA_TypeCode)&TC_char_struct) ++#define TC_wchar ((CORBA_TypeCode)&TC_wchar_struct) ++#define TC_octet ((CORBA_TypeCode)&TC_octet_struct) ++#define TC_any ((CORBA_TypeCode)&TC_any_struct) ++#define TC_TypeCode ((CORBA_TypeCode)&TC_TypeCode_struct) ++#define TC_Principal ((CORBA_TypeCode)&TC_Principal_struct) ++#define TC_Object ((CORBA_TypeCode)&TC_Object_struct) ++#define TC_string ((CORBA_TypeCode)&TC_string_struct) ++#define TC_wstring ((CORBA_TypeCode)&TC_wstring_struct) ++#define TC_CORBA_NamedValue ((CORBA_TypeCode)&TC_CORBA_NamedValue_struct) ++ ++#define TC_CORBA_short_struct TC_short_struct ++#define TC_CORBA_long_struct TC_long_struct ++#define TC_CORBA_longlong_struct TC_longlong_struct ++#define TC_CORBA_long_long_struct TC_longlong_struct ++#define TC_CORBA_ushort_struct TC_ushort_struct ++#define TC_CORBA_unsigned_short_struct TC_ushort_struct ++#define TC_CORBA_ulong_struct TC_ulong_struct ++#define TC_CORBA_unsigned_long_struct TC_ulong_struct ++#define TC_CORBA_ulonglong_struct TC_ulonglong_struct ++#define TC_CORBA_unsigned_long_long_struct TC_ulonglong_struct ++#define TC_CORBA_float_struct TC_float_struct ++#define TC_CORBA_double_struct TC_double_struct ++#define TC_CORBA_longdouble_struct TC_longdouble_struct ++#define TC_CORBA_long_double_struct TC_longdouble_struct ++#define TC_CORBA_boolean_struct TC_boolean_struct ++#define TC_CORBA_char_struct TC_char_struct ++#define TC_CORBA_wchar_struct TC_wchar_struct ++#define TC_CORBA_octet_struct TC_octet_struct ++#define TC_CORBA_any_struct TC_any_struct ++#define TC_CORBA_TypeCode_struct TC_TypeCode_struct ++#define TC_CORBA_Principal_struct TC_Principal_struct ++#define TC_CORBA_Object_struct TC_Object_struct ++#define TC_CORBA_string_struct TC_string_struct ++#define TC_CORBA_wstring_struct TC_wstring_struct ++ ++extern const struct CORBA_TypeCode_struct TC_null_struct; ++extern const struct CORBA_TypeCode_struct TC_void_struct; ++extern const struct CORBA_TypeCode_struct TC_short_struct; ++extern const struct CORBA_TypeCode_struct TC_long_struct; ++extern const struct CORBA_TypeCode_struct TC_longlong_struct; ++extern const struct CORBA_TypeCode_struct TC_ushort_struct; ++extern const struct CORBA_TypeCode_struct TC_ulong_struct; ++extern const struct CORBA_TypeCode_struct TC_ulonglong_struct; ++extern const struct CORBA_TypeCode_struct TC_float_struct; ++extern const struct CORBA_TypeCode_struct TC_double_struct; ++extern const struct CORBA_TypeCode_struct TC_longdouble_struct; ++extern const struct CORBA_TypeCode_struct TC_boolean_struct; ++extern const struct CORBA_TypeCode_struct TC_char_struct; ++extern const struct CORBA_TypeCode_struct TC_wchar_struct; ++extern const struct CORBA_TypeCode_struct TC_octet_struct; ++extern const struct CORBA_TypeCode_struct TC_any_struct; ++extern const struct CORBA_TypeCode_struct TC_TypeCode_struct; ++extern const struct CORBA_TypeCode_struct TC_Principal_struct; ++extern const struct CORBA_TypeCode_struct TC_Object_struct; ++extern const struct CORBA_TypeCode_struct TC_string_struct; ++extern const struct CORBA_TypeCode_struct TC_wstring_struct; ++extern const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct; ++ ++ ++#endif /* !_ORBIT_CORBA_TYPECODE_H_ */ ++ ++ ++ ++ +diff -urN linux-2.4.1/net/korbit/orb/corba_typecode_type.h linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h +--- linux-2.4.1/net/korbit/orb/corba_typecode_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/corba_typecode_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,66 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_CORBA_TYPECODE_TYPE_H_ ++#define _ORBIT_CORBA_TYPECODE_TYPE_H_ ++ ++#include <ORBitutil/basic_types.h> ++#include "corba_typecode.h" ++#include "corba_any.h" ++ ++typedef struct CORBA_TypeCode_Bounds { ++ int dummy; ++} CORBA_TypeCode_Bounds; ++ ++typedef struct CORBA_TypeCode_BadKind { ++ int dummy; ++} CORBA_TypeCode_BadKind; ++ ++struct CORBA_TypeCode_struct { ++ struct ORBit_PseudoObject_struct parent; ++ CORBA_TCKind kind; ++#ifndef __KORBIT__ ++ const ++#endif ++ char *name; ++#ifndef __KORBIT__ ++ const ++#endif ++ char *repo_id; ++ CORBA_unsigned_long length; ++ CORBA_unsigned_long sub_parts; ++ const char **subnames; /* for struct, exception, union, enum */ ++ CORBA_TypeCode *subtypes; /* for struct, exception, union, alias, array, sequence */ ++ CORBA_any *sublabels; /* for union */ ++ CORBA_TypeCode discriminator; /* for union */ ++ CORBA_unsigned_long recurse_depth; /* for recursive sequence */ ++ CORBA_long default_index; /* for union */ ++ CORBA_unsigned_short digits; /* for fixed */ ++ CORBA_short scale; /* for fixed */ ++}; ++ ++ ++#endif /* !_ORBIT_CORBA_TYPECODE_TYPE_H_ */ ++ +diff -urN linux-2.4.1/net/korbit/orb/dii.c linux-2.4.1-korbit/net/korbit/orb/dii.c +--- linux-2.4.1/net/korbit/orb/dii.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/dii.c Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,454 @@ ++/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Red Hat Software, Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Elliot Lee <sopwith@redhat.com> ++ * Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++#include "orbit.h" ++#ifndef __KORBIT__ ++#include "interface_repository.h" ++#endif /* !__KORBIT__ */ ++ ++struct CORBA_Request_type { ++ struct ORBit_PseudoObject_struct parent; ++ ++ CORBA_Object obj; ++ CORBA_Context ctx; ++ ++ CORBA_Flags req_flags; ++ CORBA_Identifier operation; ++ ++ CORBA_NamedValue *result; ++ CORBA_NVList *arg_list; ++ ++ CORBA_unsigned_long request_id; ++ GIOPSendBuffer *request_buffer; ++ GIOPRecvBuffer *reply_buffer; ++}; ++ ++static const ORBit_RootObject_Interface interface_CORBA_Request = { ++ (void (*)(gpointer,CORBA_Environment *))CORBA_Request_delete ++}; ++ ++/* Section 5.2.1 */ ++CORBA_Status ++CORBA_Object_create_request(CORBA_Object obj, ++ CORBA_Context ctx, ++ CORBA_Identifier operation, ++ CORBA_NVList *arg_list, ++ CORBA_NamedValue *result, ++ CORBA_Request *request, ++ CORBA_Flags req_flags, ++ CORBA_Environment *ev) ++{ ++ CORBA_Request new; ++ ++ new=g_new0(struct CORBA_Request_type, 1); ++ ORBit_pseudo_object_init((ORBit_PseudoObject)new, ORBIT_PSEUDO_REQUEST, ev); ++ ORBit_RootObject_set_interface((ORBit_RootObject)new, ++ (ORBit_RootObject_Interface *)&interface_CORBA_Request, ev); ++ ++ if(new==NULL) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_NO_MEMORY, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ new->obj=CORBA_Object_duplicate(obj, ev); ++ new->ctx=(CORBA_Context)CORBA_Object_duplicate((CORBA_Object)ctx, ev); ++ new->operation=CORBA_string_dup(operation); ++ ++ new->result=result; ++ ++ new->req_flags=req_flags; ++ new->request_id = giop_get_request_id(); ++ new->arg_list = arg_list; ++ ++ *request=(CORBA_Request)CORBA_Object_duplicate((CORBA_Object)new, ev); ++} ++ ++/* Section 5.2, 5.2.2 */ ++CORBA_Status ++CORBA_Request_add_arg(CORBA_Request req, ++ CORBA_Identifier name, ++ CORBA_TypeCode arg_type, ++ void *value, ++ CORBA_long len, ++ CORBA_Flags arg_flags, ++ CORBA_Environment *ev) ++{ ++ gpointer new_value; ++ ++ g_assert(req!=NULL); ++ ++ if((arg_flags & CORBA_IN_COPY_VALUE) && (arg_flags & CORBA_ARG_IN)) { ++ new_value = ORBit_copy_value(value, arg_type); ++ if(new_value==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ } else ++ new_value=value; ++ ++ CORBA_NVList_add_item(req->arg_list, name, arg_type, ++ new_value, len, arg_flags | req->req_flags, ev); ++} ++ ++/* Section 5.2, 5.2.3 */ ++CORBA_Status ++CORBA_Request_invoke(CORBA_Request req, ++ CORBA_Flags invoke_flags, ++ CORBA_Environment *ev) ++{ ++ CORBA_Request_send(req, invoke_flags, ev); ++ if(ev->_major == CORBA_NO_EXCEPTION) ++ CORBA_Request_get_response(req, invoke_flags, ev); ++} ++ ++/* Section 5.2, 5.2.4 */ ++CORBA_Status CORBA_Request_delete(CORBA_Request req, CORBA_Environment *ev) ++{ ++ CORBA_Object_release(req->obj, ev); ++ CORBA_Object_release((CORBA_Object)req->ctx, ev); ++ ++ if(req->operation != NULL) ++ CORBA_free(req->operation); ++ ++ if(req->arg_list != NULL) { ++ if(req->req_flags & CORBA_OUT_LIST_MEMORY) ++ CORBA_NVList_free(req->arg_list, ev); ++ else { ++ int i; ++ for(i = 0; i < req->arg_list->list->len; i++) ++ ORBit_NamedValue_free(&g_array_index(req->arg_list->list, ++ CORBA_NamedValue, i)); ++ g_array_free(req->arg_list->list, TRUE); ++ ++ g_free(req->arg_list); ++ } ++ } ++ ++ if(req->result!=NULL) ++ ORBit_NamedValue_free(req->result); ++ ++ if(req->request_buffer) ++ giop_send_buffer_unuse(req->request_buffer); ++ ++ if(req->reply_buffer) ++ giop_recv_buffer_unuse(req->reply_buffer); ++ ++ g_free(req); ++} ++ ++/* Section 5.2, 5.3.1 */ ++CORBA_Status ++CORBA_Request_send(CORBA_Request req, ++ CORBA_Flags invoke_flags, ++ CORBA_Environment *ev) ++{ ++ int i; ++ GIOPConnection *cnx; ++ ++ struct { CORBA_unsigned_long opstrlen; char opname[1]; } *opnameinfo; ++ struct iovec opvec = { NULL, 0 }; ++ ++ opvec.iov_len = strlen(req->operation)+1+sizeof(CORBA_unsigned_long); ++ ++ opnameinfo = g_malloc(strlen(req->operation)+1+sizeof(CORBA_unsigned_long)); ++ opvec.iov_base = (gpointer)opnameinfo; ++ opnameinfo->opstrlen = strlen(req->operation) + 1; ++ strcpy(opnameinfo->opname, req->operation); ++ ++ cnx = ORBit_object_get_connection(req->obj); ++ ++ g_assert(req->obj->active_profile); ++ req->request_buffer = ++ giop_send_request_buffer_use(req->obj->connection, ++ NULL, ++ req->request_id, ++ req->result?TRUE:FALSE, ++ &(req->obj->active_profile->object_key_vec), ++ &opvec, ++ &ORBit_default_principal_iovec ++ ); ++ ++ if(!req->request_buffer) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_COMM_FAILURE, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ for(i = 0; i < req->arg_list->list->len; i++) { ++ CORBA_NamedValue *nv; ++ ++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i); ++ ++ if((nv->arg_modes & CORBA_ARG_IN) ++ || (nv->arg_modes & CORBA_ARG_INOUT)) ++ ORBit_marshal_arg(req->request_buffer, ++ nv->argument._value, ++ nv->argument._type); ++ } ++ ++ giop_send_buffer_write(req->request_buffer); ++ ++ giop_send_buffer_unuse(req->request_buffer); ++ req->request_buffer = 0; ++ ++ g_free(opnameinfo); ++} ++ ++/* Section 5.3.2 */ ++CORBA_Status ++CORBA_send_multiple_requests(CORBA_Request *reqs, ++ CORBA_Environment *env, ++ CORBA_long count, ++ CORBA_Flags invoke_flags) ++{ ++ int i; ++ ++ for(i = 0; i < count; i++) ++ CORBA_Request_send(reqs[i], invoke_flags, env); ++} ++ ++void ++ORBit_handle_dii_reply(CORBA_Request req, CORBA_Environment *ev) ++{ ++ int i; ++ ++ /* XXX TODO - handle exceptions, location forwards(?), all that */ ++ req->result->argument._value = ++ ORBit_demarshal_arg(req->reply_buffer, req->result->argument._type, ++ TRUE, req->obj->orb); ++ req->result->argument._release = CORBA_TRUE; ++ ++ for(i = 0; i < req->arg_list->list->len; i++) { ++ CORBA_NamedValue *nv; ++ ++ nv = &g_array_index(req->arg_list->list, CORBA_NamedValue, i); ++ ++ if(nv->arg_modes & CORBA_ARG_INOUT) { ++ CORBA_Object_duplicate((CORBA_Object)nv->argument._type, NULL); ++ CORBA_any__free(&nv->argument, NULL, TRUE); ++ } ++ ++ if((nv->arg_modes & CORBA_ARG_OUT) ++ || (nv->arg_modes & CORBA_ARG_INOUT)) ++ nv->argument._value = ORBit_demarshal_arg(req->reply_buffer, ++ nv->argument._type, ++ TRUE, req->obj->orb); ++ } ++ ++ giop_recv_buffer_unuse(req->reply_buffer); ++ req->reply_buffer = 0; ++} ++ ++/* Section 5.2, 5.3.3 ++ * ++ * Raises: WrongTransaction ++ */ ++CORBA_Status ++CORBA_Request_get_response(CORBA_Request req, ++ CORBA_Flags response_flags, ++ CORBA_Environment *ev) ++{ ++ req->reply_buffer = giop_recv_reply_buffer_use(req->request_id, ++ !(response_flags & CORBA_RESP_NO_WAIT)); ++ ++ if(!req->reply_buffer) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_COMM_FAILURE, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ ORBit_handle_dii_reply(req, ev); ++} ++ ++/* Section 5.3.4 ++ * ++ * Raises: WrongTransaction ++ */ ++CORBA_Status ++CORBA_Request_get_next_response(CORBA_Environment *env, ++ CORBA_Flags response_flags, ++ CORBA_Request *req) ++{ ++ int i; ++ GIOPRecvBuffer *rb; ++ GArray *reqids = g_array_new(FALSE, FALSE, ++ sizeof(CORBA_unsigned_long)); ++ ++ for(i = 0; req[i]; i++) { ++ g_array_append_val(reqids, req[i]->request_id); ++ } ++ ++ rb = giop_recv_reply_buffer_use_multiple(reqids, ++ !(response_flags & CORBA_RESP_NO_WAIT)); ++ ++ if(rb) { ++ for(i = 0; i < reqids->len; i++) { ++ if(g_array_index(reqids, CORBA_unsigned_long, i) ++ == rb->message.u.reply.request_id) { ++ req[i]->reply_buffer = rb; ++ break; ++ } ++ } ++ ++ if(i < reqids->len) ++ ORBit_handle_dii_reply(req[i], env); ++ } ++ ++ g_array_free(reqids, TRUE); ++} ++ ++ ++/* Section 5.4.1 */ ++CORBA_Status ++CORBA_ORB_create_list(CORBA_ORB orb, ++ CORBA_long count, ++ CORBA_NVList **new_list, ++ CORBA_Environment *ev) ++{ ++ CORBA_NVList *new; ++ ++ new = g_new0(CORBA_NVList, 1); ++ if(new==NULL) goto new_alloc_failed; ++ ++ new->list = g_array_new(FALSE, TRUE, sizeof(CORBA_NamedValue)); ++ ++ *new_list = new; ++ ++ return; ++ ++ new_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++} ++ ++#ifndef __KORBIT__ ++/* Section 5.4.6 */ ++CORBA_Status ++CORBA_ORB_create_operation_list(CORBA_ORB orb, ++ CORBA_OperationDef oper, ++ CORBA_NVList **new_list, ++ CORBA_Environment *ev) ++{ ++ if(!new_list) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ g_warning("CORBA_ORB_create_operation_list NYI"); ++ ++ CORBA_exception_set_system(ev, ++ ex_CORBA_IMP_LIMIT, ++ CORBA_COMPLETED_NO); ++} ++#endif /* !__KORBIT__ */ ++ ++/* Section 5.4.2 */ ++CORBA_Status ++CORBA_NVList_add_item(CORBA_NVList *list, ++ CORBA_Identifier item_name, ++ CORBA_TypeCode item_type, ++ void *value, ++ CORBA_long value_len, ++ CORBA_Flags item_flags, ++ CORBA_Environment *ev) ++{ ++ CORBA_NamedValue newval; ++ ++ g_assert(list!=NULL); ++ ++ newval.name = CORBA_string_dup(item_name); ++ newval.argument._type = (CORBA_TypeCode)CORBA_Object_duplicate((CORBA_Object)item_type, ev); ++ if(item_flags & CORBA_IN_COPY_VALUE) { ++ newval.argument._value = ORBit_copy_value(value, item_type); ++ newval.argument._release = CORBA_TRUE; ++ } else { ++ newval.argument._value = value; ++ newval.argument._release = CORBA_FALSE; ++ } ++ ++ newval.len = value_len; /* Is this even useful? *sigh* */ ++ newval.arg_modes = item_flags; ++ ++ g_array_append_val(list->list, newval); ++} ++ ++void ORBit_NamedValue_free(CORBA_NamedValue *nv) ++{ ++ CORBA_free(nv->name); ++} ++ ++/* Section 5.4.3 */ ++CORBA_Status ++CORBA_NVList_free(CORBA_NVList *list, ++ CORBA_Environment *ev) ++{ ++ int i; ++ ++ CORBA_NVList_free_memory(list, ev); ++ ++ for(i = 0; i < list->list->len; i++) ++ ORBit_NamedValue_free(&g_array_index(list->list, CORBA_NamedValue, i)); ++ ++ g_array_free(list->list, TRUE); ++ ++ g_free(list); ++} ++ ++/* Section 5.4.4 */ ++CORBA_Status ++CORBA_NVList_free_memory(CORBA_NVList *list, ++ CORBA_Environment *ev) ++{ ++ int i; ++ ++ for(i = 0; i < list->list->len; i++) { ++ CORBA_free(g_array_index(list->list, CORBA_NamedValue, i).argument._value); ++ g_array_index(list->list, CORBA_NamedValue, i).argument._value = NULL; ++ CORBA_Object_release((CORBA_Object)g_array_index(list->list, CORBA_NamedValue, i).argument._type, ev); ++ g_array_index(list->list, CORBA_NamedValue, i).argument._release = CORBA_FALSE; ++ } ++} ++ ++ ++/* Section 5.4.5 */ ++CORBA_Status ++CORBA_NVList_get_count(CORBA_NVList *list, ++ CORBA_long *count, ++ CORBA_Environment *ev) ++{ ++ *count = list->list->len; ++} ++ +diff -urN linux-2.4.1/net/korbit/orb/dii.h linux-2.4.1-korbit/net/korbit/orb/dii.h +--- linux-2.4.1/net/korbit/orb/dii.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/dii.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,124 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_DII_H_ ++#define _ORBIT_DII_H_ ++ ++#include "orb/orbit_types.h" ++#ifndef __KORBIT__ ++#include "orb/interface_repository.h" ++#endif /* !__KORBIT__ */ ++ ++extern CORBA_Status CORBA_Object_create_request( ++ CORBA_Object obj, ++ CORBA_Context ctx, ++ CORBA_Identifier operation, ++ CORBA_NVList *arg_list, ++ CORBA_NamedValue *result, ++ CORBA_Request *request, ++ CORBA_Flags req_flags, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Request_add_arg( ++ CORBA_Request req, ++ CORBA_Identifier name, ++ CORBA_TypeCode arg_type, ++ void *value, ++ CORBA_long len, ++ CORBA_Flags arg_flags, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Request_invoke( ++ CORBA_Request req, ++ CORBA_Flags invoke_flags, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Request_delete( ++ CORBA_Request req, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_Request_send( ++ CORBA_Request req, ++ CORBA_Flags invoke_flags, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_send_multiple_requests( ++ CORBA_Request reqs[], ++ CORBA_Environment *env, ++ CORBA_long count, ++ CORBA_Flags invoke_flags); ++ ++extern CORBA_Status CORBA_Request_get_response( ++ CORBA_Request req, ++ CORBA_Flags response_flags, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_get_next_response( ++ CORBA_Environment *env, ++ CORBA_Flags response_flags, ++ CORBA_Request *req); ++ ++extern CORBA_Status CORBA_NVList_add_item( ++ CORBA_NVList *list, ++ CORBA_Identifier item_name, ++ CORBA_TypeCode item_type, ++ void *value, ++ CORBA_long value_len, ++ CORBA_Flags item_flags, ++ CORBA_Environment *ev); ++ ++extern void ORBit_NamedValue_free( ++ CORBA_NamedValue *nv); ++ ++ ++extern CORBA_Status CORBA_ORB_create_list( ++ CORBA_ORB orb, ++ CORBA_long count, ++ CORBA_NVList **new_list, ++ CORBA_Environment *ev); ++ ++#ifndef __KORBIT__ ++extern CORBA_Status CORBA_ORB_create_operation_list( ++ CORBA_ORB orb, ++ CORBA_OperationDef oper, ++ CORBA_NVList **new_list, ++ CORBA_Environment *ev); ++#endif /* !__KORBIT__ */ ++ ++extern CORBA_Status CORBA_NVList_free(CORBA_NVList *list, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_NVList_free_memory( ++ CORBA_NVList *list, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_NVList_get_count( ++ CORBA_NVList *list, ++ CORBA_long *count, ++ CORBA_Environment *ev); ++ ++extern const int sizeofs[], container_sizeofs[]; ++ ++#endif /* _ORBIT_DII_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/env.c linux-2.4.1-korbit/net/korbit/orb/env.c +--- linux-2.4.1/net/korbit/orb/env.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/env.c Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,345 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++/* ++ * CORBA_Environment handling functions ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <assert.h> ++ ++#include "orbit.h" ++#ifndef __KORBIT__ ++#include "interface_repository.h" ++#endif /* !__KORBIT__ */ ++ ++struct SysExInfo { ++ const char *repo_id; ++ const int exnum; ++}; ++ ++static const struct SysExInfo exception_table[] = { ++ {NULL, 0}, ++ {"IDL:CORBA/UNKNOWN:1.0", 1}, ++ {"IDL:CORBA/BAD_PARAM:1.0", 2}, ++ {"IDL:CORBA/NO_MEMORY:1.0", 3}, ++ {"IDL:CORBA/IMP_LIMIT:1.0", 4}, ++ {"IDL:CORBA/COMM_FAILURE:1.0", 5}, ++ {"IDL:CORBA/INV_OBJREF:1.0", 6}, ++ {"IDL:CORBA/NO_PERMISSION:1.0", 7}, ++ {"IDL:CORBA/INTERNAL:1.0", 8}, ++ {"IDL:CORBA/MARSHAL:1.0", 9}, ++ {"IDL:CORBA/INITIALIZE:1.0", 10}, ++ {"IDL:CORBA/NO_IMPLEMENT:1.0", 11}, ++ {"IDL:CORBA/BAD_TYPECODE:1.0", 12}, ++ {"IDL:CORBA/BAD_OPERATION:1.0", 13}, ++ {"IDL:CORBA/NO_RESOURCES:1.0", 14}, ++ {"IDL:CORBA/NO_RESPONSE:1.0", 15}, ++ {"IDL:CORBA/PERSIST_STORE:1.0", 16}, ++ {"IDL:CORBA/BAD_INV_ORDER:1.0", 17}, ++ {"IDL:CORBA/TRANSIENT:1.0", 18}, ++ {"IDL:CORBA/FREE_MEM:1.0", 19}, ++ {"IDL:CORBA/INV_IDENT:1.0", 20}, ++ {"IDL:CORBA/INV_FLAG:1.0", 21}, ++ {"IDL:CORBA/INTF_REPOS:1.0", 22}, ++ {"IDL:CORBA/BAD_CONTEXT:1.0", 23}, ++ {"IDL:CORBA/OBJ_ADAPTER:1.0", 24}, ++ {"IDL:CORBA/DATA_CONVERSION:1.0", 25}, ++ {"IDL:CORBA/OBJECT_NOT_EXIST:1.0", 26}, ++ {"IDL:CORBA/TRANSACTION_REQUIRED:1.0", 27}, ++ {"IDL:CORBA/TRANSACTION_ROLLEDBACK:1.0", 28}, ++ {"IDL:CORBA/INVALID_TRANSACTION:1.0", 29}, ++ {NULL,0} ++}; ++ ++void CORBA_exception_free(CORBA_Environment *ev) ++{ ++ g_assert(ev!=NULL); ++ ++ ev->_major=CORBA_NO_EXCEPTION; ++ ++ if(ev->_repo_id) { ++ CORBA_free(ev->_repo_id); ++ ev->_repo_id=NULL; ++ } ++ ++ if(ev->_params) { ++ CORBA_free(ev->_params); ++ ev->_params=NULL; ++ } ++ ++ if(ev->_any) { ++ CORBA_free(ev->_any); ++ ev->_any=NULL; ++ } ++} ++ ++void CORBA_exception_set(CORBA_Environment *ev, CORBA_exception_type major, ++ const CORBA_char *except_repos_id, void *param) ++{ ++ g_assert(ev!=NULL); ++ ++ if(ev->_major != CORBA_NO_EXCEPTION) ++ CORBA_exception_free(ev); ++ ++ ev->_major=major; ++ ++ if(except_repos_id==NULL) { ++ ev->_repo_id=NULL; ++ } else { ++ ev->_repo_id=CORBA_string_dup(except_repos_id); ++ } ++ ++ ev->_params=param; ++} ++ ++void CORBA_exception_set_system(CORBA_Environment *ev, CORBA_unsigned_long ex_value, ++ CORBA_completion_status completed) ++{ ++ CORBA_SystemException *new; ++ ++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL); ++ if(new!=NULL) { ++ new->minor=0; ++ new->completed=completed; ++ ++ /* XXX what should the repo ID be? */ ++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION, ++ exception_table[ex_value].repo_id, ++ new); ++ } ++} ++ ++void CORBA_exception_init(CORBA_Environment *ev) ++{ ++ g_assert(ev!=NULL); ++ ++ ev->_major=CORBA_NO_EXCEPTION; ++ ev->_repo_id=NULL; ++ ev->_params=NULL; ++ ev->_any=NULL; ++} ++ ++CORBA_char *CORBA_exception_id(CORBA_Environment *ev) ++{ ++ g_assert(ev!=NULL); ++ ++ if(ev->_major==CORBA_NO_EXCEPTION) { ++ return(NULL); ++ } else { ++ return(ev->_repo_id); ++ } ++} ++ ++void *CORBA_exception_value(CORBA_Environment *ev) ++{ ++ g_assert(ev!=NULL); ++ ++ if(ev->_major==CORBA_NO_EXCEPTION) { ++ return(NULL); ++ } else { ++ return(ev->_params); ++ } ++} ++ ++#ifndef __KORBIT__ ++CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev) ++{ ++ g_assert(ev!=NULL); ++ ++ if(ev->_major==CORBA_NO_EXCEPTION) { ++ return(NULL); ++ } ++ ++ if(ev->_any!=NULL) { ++ return(ev->_any); ++ } ++ ++ ev->_any=g_new(CORBA_any, 1); ++ if(ev->_any!=NULL) { ++ /* XXX is this the correct type? */ ++ ev->_any->_type = (CORBA_TypeCode)TC_CORBA_ExceptionDescription; ++ ev->_any->_value = ev->_params; ++ ev->_any->_release = 0; ++ } ++ ++ return(ev->_any); ++} ++#endif /* !__KORBIT__ */ ++ ++/**** ORBit_handle_exception ++ Inputs: 'rb' - a receive buffer for which an exception condition has ++ been determined ++ 'ev' - memory in which to store the exception information ++ ++ 'user_exceptions' - list of user exceptions raisable ++ for this particular operation. ++ Side-effects: reinitializes '*ev' ++ ++ Description: ++ During demarshalling a reply, if reply_status != CORBA_NO_EXCEPTION, ++ we must find out what exception was raised and place that information ++ in '*ev'. */ ++ ++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev, ++ const ORBit_exception_demarshal_info *user_exceptions, ++ CORBA_ORB orb) ++{ ++ CORBA_SystemException *new; ++ CORBA_unsigned_long len, completion_status; ++ CORBA_char *my_repoid; ++ ++ g_return_if_fail(GIOP_MESSAGE_BUFFER(rb)->message_header.message_type == GIOP_REPLY); ++ ++ CORBA_exception_free(ev); ++ ++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(len)); ++ rb->decoder(&len, rb->cur, sizeof(len)); ++ /* (guchar *)rb->cur += sizeof(len); */ ++ rb->cur = ((guchar *)rb->cur) + sizeof(len); ++ ++ if(len) { ++ my_repoid = rb->cur; ++ rb->cur = ((guchar *)rb->cur) + len; ++ } else ++ my_repoid = NULL; ++ ++ if(rb->message.u.reply.reply_status == CORBA_SYSTEM_EXCEPTION) { ++ CORBA_unsigned_long minor; ++ ++ ev->_major = CORBA_SYSTEM_EXCEPTION; ++ ++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(minor)); ++ rb->decoder(&minor, rb->cur, sizeof(minor)); ++ rb->cur = ((guchar *)rb->cur) + sizeof(minor); ++ ++ rb->cur = ALIGN_ADDRESS(rb->cur, sizeof(completion_status)); ++ rb->decoder(&completion_status, rb->cur, sizeof(completion_status)); ++ rb->cur = ((guchar *)rb->cur) + sizeof(completion_status); ++ ++ new=ORBit_alloc(sizeof(CORBA_SystemException), NULL, NULL); ++ ++ if(new!=NULL) { ++ new->minor=minor; ++ new->completed=completion_status; ++ ++ /* XXX what should the repo ID be? */ ++ CORBA_exception_set(ev, CORBA_SYSTEM_EXCEPTION, ++ my_repoid, ++ new); ++ } ++ } else if(rb->message.u.reply.reply_status == CORBA_USER_EXCEPTION) { ++ int i; ++ ++ if(!user_exceptions) { ++ /* weirdness; they raised an exception that we don't ++ know about */ ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_MAYBE); ++ } else { ++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL; ++ i++) { ++ if(!strcmp(user_exceptions[i].tc->repo_id, ++ my_repoid)) ++ break; ++ } ++ ++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) { ++ /* weirdness; they raised an exception ++ that we don't know about */ ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_MAYBE); ++ } else { ++ user_exceptions[i].demarshal(rb, ev); ++ } ++ } ++ }; ++ ++ /* ignore LOCATION_FORWARD here, that gets handled in the stub */ ++} ++ ++void ++ORBit_send_system_exception(GIOPSendBuffer *send_buffer, ++ CORBA_Environment *ev) ++{ ++ CORBA_unsigned_long minor; ++ CORBA_unsigned_long completion_status; ++ CORBA_SystemException *se = ev->_params; ++ ++ minor = se->minor; ++ completion_status = se->completed; ++ ++ ENCODER_CALL(CORBA_char, ev->_repo_id); ++ giop_send_buffer_append_mem_indirect_a(send_buffer, &minor, ++ sizeof(minor)); ++ giop_send_buffer_append_mem_indirect_a(send_buffer, ++ &completion_status, ++ sizeof(completion_status)); ++} ++ ++void ++ORBit_send_user_exception(GIOPSendBuffer *send_buffer, ++ CORBA_Environment *ev, ++ const ORBit_exception_marshal_info *user_exceptions) ++{ ++ int i; ++ ++ for(i = 0; user_exceptions[i].tc != CORBA_OBJECT_NIL; i++) { ++ if(!strcmp(user_exceptions[i].tc->repo_id, ev->_repo_id)) ++ break; ++ } ++ ++ if(user_exceptions[i].tc == CORBA_OBJECT_NIL) { ++ CORBA_Environment fakeev; ++ CORBA_exception_init(&fakeev); ++ CORBA_exception_set_system(&fakeev, ex_CORBA_UNKNOWN, ++ CORBA_COMPLETED_MAYBE); ++ ORBit_send_system_exception(send_buffer, &fakeev); ++ CORBA_exception_free(&fakeev); ++ } else { ++ ENCODER_CALL(CORBA_char, ev->_repo_id); ++ ++ if(user_exceptions[i].marshal && ev->_params) ++ user_exceptions[i].marshal(send_buffer, ev); ++ } ++} ++ ++void ++ORBit_handle_system_exception(CORBA_Environment *ev, ++ CORBA_unsigned_long system_exception_minor, ++ CORBA_unsigned_long completion_status, ++ GIOPRecvBuffer *recv_buffer, ++ GIOPSendBuffer *send_buffer) ++{ ++ CORBA_exception_set_system(ev, system_exception_minor, completion_status); ++ ++ if(send_buffer) ++ giop_send_buffer_unuse(send_buffer); ++ ++ if(recv_buffer) ++ giop_recv_buffer_unuse(recv_buffer); ++} +diff -urN linux-2.4.1/net/korbit/orb/env.h linux-2.4.1-korbit/net/korbit/orb/env.h +--- linux-2.4.1/net/korbit/orb/env.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/env.h Thu Feb 1 16:21:56 2001 +@@ -0,0 +1,79 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998, 1999 Richard H. Porter, Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_ENV_H_ ++#define _ORBIT_ENV_H_ ++ ++#include "orbit_types.h" ++ ++extern void CORBA_exception_set(CORBA_Environment *ev, ++ CORBA_exception_type major, ++ const CORBA_char *except_repos_id, ++ void *param); ++ ++extern void CORBA_exception_set_system(CORBA_Environment *ev, ++ CORBA_unsigned_long ex_value, ++ CORBA_completion_status completed); ++ ++extern void CORBA_exception_init(CORBA_Environment *ev); ++ ++extern CORBA_char *CORBA_exception_id(CORBA_Environment *e); ++ ++extern void *CORBA_exception_value(CORBA_Environment *ev); ++ ++extern void CORBA_exception_free(CORBA_Environment *ev); ++ ++#ifndef __KORBIT__ ++extern CORBA_any *CORBA_exception_as_any(CORBA_Environment *ev); ++#endif /* !__KORBIT__ */ ++ ++typedef struct { ++ const CORBA_TypeCode tc; ++ void (*demarshal)(GIOPRecvBuffer *_ORBIT_recv_buffer, CORBA_Environment *ev); ++} ORBit_exception_demarshal_info; ++ ++typedef struct { ++ const CORBA_TypeCode tc; ++ void (*marshal)(GIOPSendBuffer *_ORBIT_send_buffer, CORBA_Environment *ev); ++} ORBit_exception_marshal_info; ++ ++/* ORBit-specific */ ++void ORBit_handle_exception(GIOPRecvBuffer *rb, CORBA_Environment *ev, ++ const ORBit_exception_demarshal_info *user_exceptions, ++ CORBA_ORB orb); ++void ORBit_send_system_exception(GIOPSendBuffer *send_buffer, ++ CORBA_Environment *ev); ++void ORBit_send_user_exception(GIOPSendBuffer *send_buffer, ++ CORBA_Environment *ev, ++ const ORBit_exception_marshal_info *user_exceptions); ++ ++/* Used by stubs */ ++void ORBit_handle_system_exception(CORBA_Environment *ev, ++ CORBA_unsigned_long system_exception_minor, ++ CORBA_unsigned_long completion_status, ++ GIOPRecvBuffer *recv_buffer, ++ GIOPSendBuffer *send_buffer); ++ ++#endif /* !_ORBIT_ENV_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/genrand.c linux-2.4.1-korbit/net/korbit/orb/genrand.c +--- linux-2.4.1/net/korbit/orb/genrand.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/genrand.c Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,131 @@ ++#include "genrand.h" ++#include "ORBitutil/util.h" ++#include <unistd.h> ++#include <sys/types.h> ++#include <fcntl.h> ++#include <glib.h> ++#include <signal.h> ++#include <sys/time.h> ++#include <limits.h> ++#include <stdio.h> ++#ifdef __KERNEL__ ++#include <linux/random.h> ++#endif ++ ++static gboolean ++genrand_dev(guchar *buffer, int buf_len) ++{ ++#ifdef __KERNEL__ ++ get_random_bytes(buffer, buf_len); ++#else /*! __KERNEL__*/ ++ int fd; ++ ++ fd = open("/dev/urandom", O_RDONLY); ++ if(fd < 0) ++ return FALSE; ++ ++ if(read(fd, buffer, buf_len) < buf_len) ++ { ++ close(fd); ++ return FALSE; ++ } ++ ++ close(fd); ++#endif /*! __KERNEL__*/ ++ ++ return TRUE; ++} ++ ++#ifndef __KORBIT__ ++static volatile int received_alarm = 0; ++ ++static void ++handle_alarm(int signum) ++{ ++ received_alarm = 1; ++} ++ ++static inline guchar ++hashlong(long val) ++{ ++ guchar retval, *ptr; ++ int i; ++ ++ for(ptr = (guchar *)&val, i = 0; i < sizeof(val); i++) ++ retval ^= ptr[i]; ++ ++ return retval; ++} ++ ++static gboolean ++genrand_unix(guchar *buffer, int buf_len) ++{ ++ struct sigaction sa, oldsa; ++ struct itimerval it, oldit; ++ int i; ++ long min, max; ++ long *counts; ++ double diff; ++ long *uninit; ++ ++ counts = alloca(buf_len * sizeof(long)); ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_handler = handle_alarm; ++ sigaction(SIGALRM, &sa, &oldsa); ++ memset(&it, 0, sizeof(it)); ++ it.it_value.tv_usec = 1; ++ getitimer(ITIMER_REAL, &oldit); ++ ++ for(i = 0, min = LONG_MAX, max = 0; i < buf_len; i++) ++ { ++ received_alarm = 0; ++ setitimer(ITIMER_REAL, &it, NULL); ++ for(counts[i] = 0; !received_alarm; counts[i]++); ++ ++ max = MAX(counts[i], max); ++ min = MIN(counts[i], min); ++ } ++ ++ if(!(max - min)) ++ { ++ freeca(counts); ++ return FALSE; ++ } ++ ++ diff = max - min; ++ ++ uninit = alloca(buf_len * sizeof(long)); /* Purposely not initialized */ ++ for(i = 0; i < buf_len; i++) ++ { ++ long diffval; ++ diffval = counts[i] - min; ++ ++ buffer[i] ^= (guchar)( ((double) (diffval*256) / diff )) ^ hashlong(uninit[i]); ++ } ++ ++ setitimer(ITIMER_REAL, &oldit, NULL); ++ sigaction(SIGALRM, &oldsa, NULL); ++ ++ freeca(counts); ++ freeca(uninit); ++ ++ return TRUE; ++} ++#endif /* !__KORBIT__ */ ++ ++void ++orbit_genrand(guchar *buffer, int buf_len) ++{ ++ g_return_if_fail(buf_len); ++ ++ if(genrand_dev(buffer, buf_len)) ++ return; ++#ifndef __KORBIT__ ++ else if(genrand_unix(buffer, buf_len)) ++ return; ++#endif ++ else ++ g_error("Couldn't generate random data!"); ++} ++ +diff -urN linux-2.4.1/net/korbit/orb/genrand.h linux-2.4.1-korbit/net/korbit/orb/genrand.h +--- linux-2.4.1/net/korbit/orb/genrand.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/genrand.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,8 @@ ++#ifndef ORBIT_GENRAND_H ++#define ORBIT_GENRAND_H 1 ++ ++#include <glib.h> ++ ++void orbit_genrand(guchar *buffer, int buf_len); ++ ++#endif /* ORBIT_GENRAND_H */ +diff -urN linux-2.4.1/net/korbit/orb/iop.h linux-2.4.1-korbit/net/korbit/orb/iop.h +--- linux-2.4.1/net/korbit/orb/iop.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/iop.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,207 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_IOP_H_ ++#define _ORBIT_IOP_H_ ++ ++#include <ORBitutil/basic_types.h> ++ ++#include <orb/corba_basic_sequences_type.h> ++ ++#ifndef HAVE_CORBA_PRINCIPAL ++#define HAVE_CORBA_PRINCIPAL 1 ++typedef CORBA_sequence_octet CORBA_Principal; ++#endif ++ ++typedef CORBA_unsigned_long IOP_ProfileId; ++ ++#define IOP_TAG_INTERNET_IOP 0 ++#define IOP_TAG_MULTIPLE_COMPONENTS 1 ++#define IOP_TAG_ORBIT_SPECIFIC 0xbadfaecal ++ ++typedef struct IOP_TaggedProfile { ++ IOP_ProfileId tag; ++ CORBA_sequence_octet profile_data; ++} IOP_TaggedProfile; ++ ++typedef struct CORBA_sequence_TaggedProfile { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ IOP_TaggedProfile *_buffer; ++} CORBA_sequence_TaggedProfile; ++ ++typedef struct IOP_IOR { ++ CORBA_char *type_id; ++ CORBA_sequence_TaggedProfile profiles; ++} IOP_IOR; ++ ++typedef CORBA_unsigned_long IOP_ComponentId; ++ ++typedef struct IOP_TaggedComponent { ++ IOP_ComponentId tag; ++ CORBA_sequence_octet component_data; ++} IOP_TaggedComponent; ++ ++typedef struct CORBA_sequence_TaggedComponent { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ IOP_TaggedComponent *_buffer; ++} CORBA_sequence_TaggedComponent; ++ ++typedef struct CORBA_sequence_TaggedComponent IOP_MultipleComponentProfile; ++ ++#define IOP_TAG_ORB_TYPE 0 ++#define IOP_TAG_CODE_SETS 1 ++#define IOP_TAG_SEC_NAME 14 ++#define IOP_TAG_ASSOCIATION_OPTIONS 13 ++#define IOP_TAG_GENERIC_SEC_MECH 12 ++ ++typedef CORBA_unsigned_long IOP_ServiceId; ++ ++typedef struct IOP_ServiceContext { ++ IOP_ServiceId context_id; ++ CORBA_sequence_octet context_data; ++} IOP_ServiceContext; ++ ++typedef struct CORBA_sequence_ServiceContext { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ IOP_ServiceContext *_buffer; ++} CORBA_sequence_ServiceContext; ++ ++typedef struct CORBA_sequence_ServiceContext IOP_ServiceContextList; ++ ++#define IOP_TransactionService 0 ++#define IOP_CodeSets 1 ++ ++typedef CORBA_unsigned_long CONV_FRAME_CodeSetId; ++ ++typedef struct CORBA_sequence_CodeSetId { ++ CORBA_unsigned_long _maximum; ++ CORBA_unsigned_long _length; ++ CONV_FRAME_CodeSetId *_buffer; ++} CORBA_sequence_CodeSetId; ++ ++typedef struct CONV_FRAME_CodeSetComponent { ++ CONV_FRAME_CodeSetId native_code_set; ++ CORBA_sequence_CodeSetId conversion_code_sets; ++} CONV_FRAME_CodeSetComponent; ++ ++typedef struct CONV_FRAME_CodeSetComponentInfo { ++ CONV_FRAME_CodeSetComponent ForCharData; ++ CONV_FRAME_CodeSetComponent ForWcharData; ++} CONV_FRAME_CodeSetComponentInfo; ++ ++typedef struct CONV_FRAME_CodeSetContext { ++ CONV_FRAME_CodeSetId char_data; ++ CONV_FRAME_CodeSetId wchar_data; ++} CONV_FRAME_CodeSetContext; ++ ++typedef struct GIOP_Version { ++ CORBA_octet major; ++ CORBA_octet minor; ++} GIOP_Version; ++ ++typedef enum { ++ GIOP_Request=0, ++ GIOP_Reply, ++ GIOP_CancelRequest, ++ GIOP_LocateRequest, ++ GIOP_LocateReply, ++ GIOP_CloseConnection, ++ GIOP_MessageError ++} GIOP_MsgType_1_0; ++ ++typedef struct GIOP_MessageHeader_1_0 { ++ CORBA_char magic[4]; ++ GIOP_Version GIOP_version; ++ CORBA_boolean byte_order; ++ CORBA_octet message_type; ++ CORBA_unsigned_long message_size; ++} GIOP_MessageHeader_1_0; ++ ++typedef struct GIOP_MessageHeader_1_1 { ++ CORBA_char magic[4]; ++ GIOP_Version GIOP_version; ++ CORBA_octet flags; ++ CORBA_octet message_type; ++ CORBA_unsigned_long message_size; ++} GIOP_MessageHeader_1_1; ++ ++typedef struct GIOP_RequestHeader_1_0 { ++ IOP_ServiceContextList service_context; ++ CORBA_unsigned_long request_id; ++ CORBA_boolean response_expected; ++ CORBA_sequence_octet object_key; ++ CORBA_char *operation; ++ CORBA_Principal requesting_principal; ++} GIOP_RequestHeader_1_0; ++ ++typedef struct GIOP_RequestHeader_1_1 { ++ IOP_ServiceContextList service_context; ++ CORBA_unsigned_long request_id; ++ CORBA_boolean response_expected; ++ CORBA_octet reserved[3]; ++ CORBA_sequence_octet object_key; ++ CORBA_char *operation; ++ CORBA_Principal requesting_principal; ++} GIOP_RequestHeader_1_1; ++ ++typedef struct GIOP_SystemExceptionReplyBody { ++ CORBA_char *exception_id; ++ CORBA_unsigned_long minor_code_value; ++ CORBA_unsigned_long completion_status; ++} GIOP_SystemExceptionReplyBody; ++ ++typedef struct GIOP_CancelRequestHeader { ++ CORBA_unsigned_long request_id; ++} GIOP_CancelRequestHeader; ++ ++typedef struct GIOP_LocateRequestHeader { ++ CORBA_unsigned_long request_id; ++ CORBA_sequence_octet object_key; ++} GIOP_LocateRequestHeader; ++ ++typedef struct IIOP_Version { ++ CORBA_octet major; ++ CORBA_octet minor; ++} IIOP_Version; ++ ++typedef struct IIOP_ProfileBody_1_0 { ++ IIOP_Version iiop_version; ++ CORBA_char *host; ++ CORBA_unsigned_short port; ++ CORBA_sequence_octet object_key; ++} IIOP_ProfileBody_1_0; ++ ++typedef struct IIOP_ProfileBody_1_1 { ++ IIOP_Version iiop_version; ++ CORBA_char *host; ++ CORBA_unsigned_short port; ++ CORBA_sequence_octet object_key; ++ CORBA_sequence_TaggedComponent components; ++} IIOP_ProfileBody_1_1; ++ ++#endif /* !_ORBIT_IOP_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/ir.c linux-2.4.1-korbit/net/korbit/orb/ir.c +--- linux-2.4.1/net/korbit/orb/ir.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/ir.c Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,293 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#include <stdlib.h> ++#include <assert.h> ++ ++#include "orbit.h" ++ ++/* FIXME: Right now this function doesn't record whether or not it has ++ already visited a given TypeCode. I'm not sure if every recursive ++ type will have a tk_recursive node in it; if not, then this will ++ need to be reworked a bit. */ ++CORBA_boolean CORBA_TypeCode_equal(CORBA_TypeCode obj, CORBA_TypeCode tc, CORBA_Environment *ev) ++{ ++ int i; ++ ++ g_return_val_if_fail(obj!=NULL, CORBA_FALSE); ++ g_return_val_if_fail(tc!=NULL, CORBA_FALSE); ++ ++ if (obj->kind != tc->kind) { ++ return CORBA_FALSE; ++ } ++ ++ switch (obj->kind) { ++ case CORBA_tk_wstring: ++ case CORBA_tk_string: ++ return obj->length == tc->length; ++ case CORBA_tk_objref: ++ return ! strcmp (obj->repo_id, tc->repo_id); ++ case CORBA_tk_except: ++ case CORBA_tk_struct: ++ if (strcmp (obj->repo_id, tc->repo_id) ++ || obj->sub_parts != tc->sub_parts) ++ return CORBA_FALSE; ++ for (i = 0; i < obj->sub_parts; ++i) ++ if (! CORBA_TypeCode_equal (obj->subtypes[i], ++ tc->subtypes[i], ev)) ++ return CORBA_FALSE; ++ break; ++ case CORBA_tk_union: ++ if (strcmp (obj->repo_id, tc->repo_id) ++ || obj->sub_parts != tc->sub_parts ++ || ! CORBA_TypeCode_equal (obj->discriminator, ++ tc->discriminator, ev) ++ || obj->default_index != tc->default_index) ++ return CORBA_FALSE; ++ for (i = 0; i < obj->sub_parts; ++i) ++ ++ if (! CORBA_TypeCode_equal (obj->subtypes[i], ++ tc->subtypes[i], ev) ++ || ! ORBit_any_equivalent (obj->sublabels[i], ++ tc->sublabels[i], ev)) ++ return CORBA_FALSE; ++ ++ break; ++ case CORBA_tk_enum: ++ if (obj->sub_parts != tc->sub_parts ++ || strcmp (obj->repo_id, tc->repo_id)) ++ return CORBA_FALSE; ++ for (i = 0; i < obj->sub_parts; ++i) ++ if (strcmp (obj->subnames[i], tc->subnames[i])) ++ return CORBA_FALSE; ++ break; ++ case CORBA_tk_sequence: ++ case CORBA_tk_array: ++ if (obj->length != tc->length) ++ return CORBA_FALSE; ++ g_assert (obj->sub_parts == 1); ++ g_assert (tc->sub_parts == 1); ++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0], ++ ev); ++ case CORBA_tk_alias: ++ if (strcmp (obj->repo_id, tc->repo_id)) ++ return CORBA_FALSE; ++ ++ g_assert (obj->sub_parts == 1); ++ g_assert (tc->sub_parts == 1); ++ ++ return CORBA_TypeCode_equal (obj->subtypes[0], tc->subtypes[0], ++ ev); ++ break; ++ case CORBA_tk_recursive: ++ return obj->recurse_depth == tc->recurse_depth; ++ case CORBA_tk_fixed: ++ return obj->digits == tc->digits && obj->scale == tc->scale; ++ ++ default: ++ /* Everything else is primitive. */ ++ break; ++ } ++ ++ return CORBA_TRUE; ++} ++ ++CORBA_TCKind CORBA_TypeCode_kind(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ return obj->kind; ++} ++ ++static void bad_kind (CORBA_Environment *ev) ++{ ++ CORBA_TypeCode_BadKind *err; ++ err = g_new (CORBA_TypeCode_BadKind, 1); ++ if (err == NULL) { ++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY, ++ CORBA_COMPLETED_NO); ++ } else { ++ err->dummy = 23; ++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ++ "IDL:omg.org/CORBA/TypeCode/BadKind/1.0", ++ err); ++ } ++} ++ ++CORBA_RepositoryId CORBA_TypeCode_id(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct ++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias ++ || obj->kind == CORBA_tk_except)) { ++ bad_kind (ev); ++ return NULL; ++ } ++ return obj->repo_id; ++} ++ ++CORBA_Identifier CORBA_TypeCode_name(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_objref || obj->kind == CORBA_tk_struct ++ || obj->kind == CORBA_tk_enum || obj->kind == CORBA_tk_alias ++ || obj->kind == CORBA_tk_except)) { ++ bad_kind (ev); ++ return NULL; ++ } ++ ++ return obj->name; ++} ++ ++CORBA_unsigned_long CORBA_TypeCode_member_count(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union ++ || obj->kind == CORBA_tk_enum)) { ++ bad_kind (ev); ++ return 0; ++ } ++ return obj->sub_parts; ++} ++ ++static void bounds_error (CORBA_Environment *ev) ++{ ++ CORBA_TypeCode_Bounds *err; ++ err = g_new (CORBA_TypeCode_Bounds, 1); ++ if (err == NULL) { ++ CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY, ++ CORBA_COMPLETED_NO); ++ } else { ++ err->dummy = 23; ++ CORBA_exception_set (ev, CORBA_USER_EXCEPTION, ++ "IDL:omg.org/CORBA/TypeCode/Bounds/1.0", ++ err); ++ } ++} ++ ++CORBA_Identifier CORBA_TypeCode_member_name(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union ++ || obj->kind == CORBA_tk_enum)) { ++ bad_kind (ev); ++ return NULL; ++ } ++ if (index > obj->sub_parts) { ++ bounds_error (ev); ++ return NULL; ++ } ++ return obj->subnames[index]; ++} ++ ++CORBA_TypeCode CORBA_TypeCode_member_type(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_struct || obj->kind == CORBA_tk_union ++ || obj->kind == CORBA_tk_enum)) { ++ bad_kind (ev); ++ return NULL; ++ } ++ if (index > obj->sub_parts) { ++ bounds_error (ev); ++ return NULL; ++ } ++ return obj->subtypes[index]; ++} ++ ++CORBA_any *CORBA_TypeCode_member_label(CORBA_TypeCode obj, CORBA_unsigned_long index, CORBA_Environment *ev) ++{ ++ if (obj->kind != CORBA_tk_union) { ++ bad_kind (ev); ++ return NULL; ++ } ++ if (index > obj->sub_parts) { ++ bounds_error (ev); ++ return NULL; ++ } ++ return &obj->sublabels[index]; ++} ++ ++CORBA_TypeCode CORBA_TypeCode_discriminator_type(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (obj->kind != CORBA_tk_union) { ++ bad_kind (ev); ++ return NULL; ++ } ++ return obj->discriminator; ++} ++ ++CORBA_long CORBA_TypeCode_default_index(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (obj->kind != CORBA_tk_union) { ++ bad_kind (ev); ++ return 0; ++ } ++ return obj->default_index; ++} ++ ++CORBA_unsigned_long CORBA_TypeCode_length(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_string || obj->kind == CORBA_tk_wstring ++ || obj->kind == CORBA_tk_array)) { ++ bad_kind (ev); ++ return 0; ++ } ++ return obj->length; ++} ++ ++CORBA_TypeCode CORBA_TypeCode_content_type(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (! (obj->kind == CORBA_tk_sequence || obj->kind == CORBA_tk_array ++ || obj->kind == CORBA_tk_alias)) { ++ bad_kind (ev); ++ return NULL; ++ } ++ g_assert (obj->sub_parts == 1); ++ return obj->subtypes[0]; ++} ++ ++CORBA_unsigned_short CORBA_TypeCode_fixed_digits(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (obj->kind != CORBA_tk_fixed) { ++ bad_kind (ev); ++ return 0; ++ } ++ return obj->digits; ++} ++ ++CORBA_short CORBA_TypeCode_fixed_scale(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ if (obj->kind != CORBA_tk_fixed) { ++ bad_kind (ev); ++ return 0; ++ } ++ return obj->scale; ++} ++ ++CORBA_long CORBA_TypeCode_param_count(CORBA_TypeCode obj, CORBA_Environment *ev) ++{ ++ g_assert(!"Deprecated"); ++ return(0); ++} ++ ++CORBA_any *CORBA_TypeCode_parameter(CORBA_TypeCode obj, CORBA_long index, CORBA_Environment *ev) ++{ ++ g_assert(!"Deprecated"); ++ return(NULL); ++} +diff -urN linux-2.4.1/net/korbit/orb/ir.h linux-2.4.1-korbit/net/korbit/orb/ir.h +--- linux-2.4.1/net/korbit/orb/ir.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/ir.h Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,100 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_IR_H_ ++#define _ORBIT_IR_H_ ++ ++#include "orbit_types.h" ++ ++extern CORBA_boolean CORBA_TypeCode_equal( ++ CORBA_TypeCode obj, ++ CORBA_TypeCode tc, ++ CORBA_Environment *ev); ++ ++extern CORBA_TCKind CORBA_TypeCode_kind( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_RepositoryId CORBA_TypeCode_id( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Identifier CORBA_TypeCode_name( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_unsigned_long CORBA_TypeCode_member_count( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Identifier CORBA_TypeCode_member_name( ++ CORBA_TypeCode obj, ++ CORBA_unsigned_long index, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_TypeCode_member_type( ++ CORBA_TypeCode obj, ++ CORBA_unsigned_long index, ++ CORBA_Environment *ev); ++ ++extern CORBA_any *CORBA_TypeCode_member_label( ++ CORBA_TypeCode obj, ++ CORBA_unsigned_long index, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_TypeCode_discriminator_type( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_long CORBA_TypeCode_default_index( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_unsigned_long CORBA_TypeCode_length( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_TypeCode_content_type( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_unsigned_short CORBA_TypeCode_fixed_digits( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_short CORBA_TypeCode_fixed_scale( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_long CORBA_TypeCode_param_count( ++ CORBA_TypeCode obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_any *CORBA_TypeCode_parameter( ++ CORBA_TypeCode obj, ++ CORBA_long index, ++ CORBA_Environment *ev); ++ ++#endif /* !_ORBIT_IR_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/options.c linux-2.4.1-korbit/net/korbit/orb/options.c +--- linux-2.4.1/net/korbit/orb/options.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/options.c Thu Feb 1 11:47:12 2001 +@@ -0,0 +1,160 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++/* ++ * Option parsing ++ * ++ * All ORB options are stripped from the application's argv, and argc is ++ * adjusted accordingly ++ */ ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++#include <glib.h> ++ ++#include "options.h" ++ ++#ifndef __KORBIT__ ++void ORBit_option_set(ORBit_orb_options *option, const char *val) ++{ ++ g_assert(option!=NULL); ++ ++ if(option->type==no_arg && option->arg!=NULL) { ++ /* Treat as an int arg with val=1 ++ */ ++ int *int_arg=(int *)option->arg; ++ ++ *int_arg=1; ++ } else { ++ if(option->type==string_arg && option->arg!=NULL) { ++ char **str_arg=(char **)option->arg; ++ ++ /* free any existing value */ ++ if(*str_arg!=NULL) { ++ g_free(*str_arg); ++ } ++ *str_arg=g_strdup(val); ++ } else if(option->type==int_arg && option->arg!=NULL) { ++ int *int_arg=(int *)option->arg; ++ ++ *int_arg=atoi(val); ++ } ++ ++ } ++} ++ ++void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options) ++{ ++ int i,j,numargs; ++ char name[1024], *val; ++ ORBit_orb_options *search=NULL; ++ int *erase; ++ ++ numargs=*argc; ++ ++ erase=g_new0(int, *argc); ++ ++ for(i=1; i< *argc; i++) { ++ if(argv[i][0]!='-') { ++ if(search==NULL) { ++ /* Skip non-option */ ++ continue; ++ } else { ++ /* an required option value has been found */ ++ erase[i]=1; ++ numargs-=1; ++ ++ if(search->arg==NULL) { ++ /* dont store any values, just strip ++ * the argv ++ */ ++ search=NULL; ++ continue; ++ } ++ ++ ORBit_option_set(search, argv[i]); ++ ++ search=NULL; ++ continue; ++ } ++ } else { ++ if(search!=NULL && ++ (search->type==string_arg || search->type==int_arg)) { ++ fprintf(stderr, "Option %s requires an argument\n", search->name); ++ } ++ } ++ ++ val=argv[i]; ++ while(*val && *val=='-') ++ val++; ++ ++ strncpy(name,val,1023); ++ name[1023]='\0'; ++ ++ val=strchr(name, '='); ++ if(val!=NULL) { ++ *val++='\0'; ++ } ++ ++ for(search=options;search->name!=NULL;search++) { ++ if(!strcmp(name, search->name)) { ++ break; ++ } ++ } ++ ++ if(search->name==NULL) { ++ /* Didn't find it in our list of interesting options */ ++ search=NULL; ++ } else { ++ /* Found it */ ++ erase[i]=1; ++ numargs-=1; ++ ++ if(search->type==no_arg || val!=NULL) { ++ ORBit_option_set(search, val); ++ search=NULL; ++ } ++ } ++ } ++ ++ j=1; ++ for(i=1; i< *argc; i++) { ++ if(erase[i]==1) { ++ continue; ++ } else { ++ if(j<numargs) { ++ argv[j++]=argv[i]; ++ } else { ++ argv[j++]='\0'; ++ } ++ } ++ } ++ ++ *argc=numargs; ++ ++ g_free(erase); ++} ++#endif /* !__KORBIT__ */ +diff -urN linux-2.4.1/net/korbit/orb/options.h linux-2.4.1-korbit/net/korbit/orb/options.h +--- linux-2.4.1/net/korbit/orb/options.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/options.h Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,46 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_OPTIONS_H_ ++#define _ORBIT_OPTIONS_H_ ++ ++typedef enum { ++ no_arg=0, ++ string_arg, ++ int_arg ++} ORBit_opt_type; ++ ++typedef struct { ++ char *name; ++ ORBit_opt_type type; ++ void *arg; ++} ORBit_orb_options; ++ ++#ifndef __KORBIT__ ++extern void ORBit_option_set(ORBit_orb_options *found, const char *val); ++extern void ORBit_option_parse(int *argc, char **argv, ORBit_orb_options *options); ++#endif ++ ++#endif /* !_ORBIT_OPTIONS_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orb.c linux-2.4.1-korbit/net/korbit/orb/orb.c +--- linux-2.4.1/net/korbit/orb/orb.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orb.c Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,1700 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++#define o_return_val_if_fail(expr, val) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return (val); } ++#define o_return_if_fail(expr) if(!(expr)) { CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, CORBA_COMPLETED_NO); return; } ++ ++#include "config.h" ++ ++#include <unistd.h> ++#include <errno.h> ++#include <sys/stat.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++#include <ctype.h> ++#include <assert.h> ++#include <pwd.h> ++#include <time.h> ++#include <sys/types.h> ++#include <dirent.h> ++#include <sys/types.h> ++#include <sys/socket.h> ++#include <sys/un.h> ++#include <utime.h> ++ ++#include "../IIOP/iiop-endianP.h" ++#include "orbit.h" ++ ++#include "orbit_poa.h" ++#include "orbit_object.h" ++#include "orbit_object_type.h" ++ ++#ifndef __KERNEL__ ++#define freeca(ptr) ++#endif ++ ++#ifndef SUN_LEN ++/* This system is not POSIX.1g. */ ++#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ ++ + strlen ((ptr)->sun_path)) ++#endif ++ ++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev); ++ ++static const ORBit_RootObject_Interface CORBA_ORB_epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))ORBit_ORB_release ++}; ++ ++ ++static int ORBit_ORBid_setup(CORBA_ORB orb, CORBA_ORBid id) ++{ ++ g_assert(orb!=NULL); ++ g_assert(id!=NULL); ++ ++ if(strcmp(id, "orbit-local-orb")) { ++#ifdef __KORBIT__ ++ printf("ORBit_ORBid_setup: Unknown ORB id: %s\n", id); ++#else ++ fprintf(stderr, "ORBit_ORBid_setup: Unknown ORB id: %s\n", id); ++#endif ++ return(0); ++ } ++ ++ orb->orb_identifier=g_strdup(id); ++ ++ return(1); ++} ++ ++#ifndef __KORBIT__ ++static gboolean ++free_key_and_data(gpointer key, gpointer data, gpointer user_data) ++{ ++ g_free(key); g_free(data); ++ ++ return TRUE; ++} ++ ++static void ORBit_rc_load(const char *rcfile, ORBit_orb_options *options) ++{ ++ FILE *fp; ++ GHashTable *read_options; ++ ORBit_orb_options *search; ++ ++ fp=fopen(rcfile, "r"); ++ ++ if(fp==NULL) ++ return; ++ ++ read_options=g_hash_table_new(g_str_hash, g_str_equal); ++ ++ while(!feof(fp)) { ++ char buf[1024]; ++ ++ if(fgets(buf, 1024, fp)!=NULL) { ++ guchar *bptr, *tmp, *key, *data; ++ size_t start, len; ++ ++ if(buf[0]=='#') ++ continue; ++ ++ bptr=buf; ++ tmp=strpbrk(bptr, " \t\n="); ++ if(tmp==NULL) continue; ++ *tmp++='\0'; ++ key=g_strdup(bptr); ++ bptr=tmp; ++ ++ start=0; ++ while(bptr+start != '\0' && ++ (isspace(bptr[start]) || bptr[start]=='=')) ++ start++; ++ len=strcspn(bptr+start, " \t\n"); ++ bptr[start+len]='\0'; ++ if(len>0) { ++ data=g_strdup(bptr+start); ++ } else { ++ data=g_strdup("TRUE"); ++ } ++ ++ g_hash_table_insert(read_options, key, data); ++ } ++ } ++ fclose(fp); ++ ++ for(search=options;search->name!=NULL;search++) { ++ char *read_val; ++ ++ read_val=g_hash_table_lookup(read_options, search->name); ++ if(read_val!=NULL) { ++ ORBit_option_set(search, read_val); ++ } ++ } ++ ++ g_hash_table_foreach_remove(read_options, free_key_and_data, NULL); ++ g_hash_table_destroy(read_options); ++} ++#endif /* !__KORBIT__ */ ++ ++static void ORBit_ORB_release(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ g_assert(orb!=NULL); ++ ++ if(--(ORBIT_ROOT_OBJECT(orb)->refs)) ++ return; ++ ++ if(orb->orb_identifier!=NULL) { ++ g_free(orb->orb_identifier); ++ } ++ if(!CORBA_Object_is_nil(orb->imr, ev)) { ++ CORBA_Object_release(orb->imr, ev); ++ } ++ if(!CORBA_Object_is_nil(orb->ir, ev)) { ++ CORBA_Object_release(orb->ir, ev); ++ } ++ if(!CORBA_Object_is_nil(orb->naming, ev)) { ++ CORBA_Object_release(orb->naming, ev); ++ } ++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) { ++ CORBA_Object_release(orb->root_poa, ev); ++ } ++ if(orb->cnx.ipv4) ++ giop_connection_unref(orb->cnx.ipv4); ++ if(orb->cnx.ipv6) ++ giop_connection_unref(orb->cnx.ipv6); ++#ifndef __KORBIT__ ++ if(orb->cnx.usock) ++ giop_connection_unref(orb->cnx.usock); ++#endif ++ ++ g_free(orb); ++} ++ ++#ifndef __KORBIT__ ++static GIOPConnection* ++ORBit_ORB_make_usock_connection(void) ++{ ++ GIOPConnection *retval = NULL; ++ GString *tmpstr; ++ struct stat statbuf; ++ ++ tmpstr = g_string_new(NULL); ++ ++ g_string_sprintf(tmpstr, "/tmp/orbit-%s", g_get_user_name()); ++ ++ if(mkdir(tmpstr->str, 0700) != 0) { ++ int e = errno; ++ ++ switch (e) { ++ case 0: ++ case EEXIST: ++ if (stat(tmpstr->str, &statbuf) != 0) ++ g_error ("Can not stat %s\n", tmpstr->str); ++ ++ if (statbuf.st_uid != getuid ()) ++ g_error ("Owner of %s is not the current user\n", ++ tmpstr->str); ++ ++ if((statbuf.st_mode & (S_IRWXG|S_IRWXO)) ++ || !S_ISDIR(statbuf.st_mode)) ++ g_error ("Wrong permissions for %s\n", ++ tmpstr->str); ++ break; ++ ++ default: ++ g_error("Unknown error on directory creation of %s (%s)\n", ++ tmpstr->str, g_strerror (e)); ++ } ++ } ++ ++ { ++ struct utimbuf utb; ++ memset(&utb, 0, sizeof(utb)); ++ utime(tmpstr->str, &utb); ++ } ++ ++ ++#ifdef WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS ++ g_string_sprintf(tmpstr, "/tmp/orbit-%s", ++ g_get_user_name()); ++ dirh = opendir(tmpstr->str); ++ while(!retval && (dent = readdir(dirh))) { ++ int usfd, ret; ++ struct sockaddr_un saddr; ++ ++ saddr.sun_family = AF_UNIX; ++ ++ if(strncmp(dent->d_name, "orb-", 4)) ++ continue; ++ ++ g_snprintf(saddr.sun_path, sizeof(saddr.sun_path), ++ "/tmp/orbit-%s/%s", ++ g_get_user_name(), dent->d_name); ++ ++ usfd = socket(AF_UNIX, SOCK_STREAM, 0); ++ g_assert(usfd >= 0); ++ ++ ret = connect(usfd, &saddr, SUN_LEN(&saddr)); ++ close(usfd); ++ ++ if(ret >= 0) ++ continue; ++ ++ unlink(saddr.sun_path); ++ } ++ closedir(dirh); ++#endif /* WE_DONT_CARE_ABOUT_STUPID_2DOT0DOTX_KERNELS */ ++ ++ srand(time(NULL)); ++ while(!retval) { ++ g_string_sprintf(tmpstr, "/tmp/orbit-%s/orb-%d%d", ++ g_get_user_name(), rand(), rand()); ++ retval = ++ GIOP_CONNECTION(iiop_connection_server_unix(tmpstr->str)); ++ } ++ ++ g_string_free(tmpstr, TRUE); ++ ++ return retval; ++} ++#endif /* !__KORBIT__ */ ++ ++ ++// Synchronize between the user process starting up the orb and the ORB thread ++// this mutex gets released when the orb is all fired up and ready to go. ++static DECLARE_MUTEX(StartupSem); ++static CORBA_ORB TheOneTrueOrb = 0; ++ ++struct CORBA_ORB_init_args { // A pointer to this struct is passed to ++ int *argc; // __CORBA_ORB_init ++ char **argv; ++ CORBA_ORBid orb_identifier; ++ CORBA_Environment *ev; ++}; ++ ++ ++CORBA_ORB __CORBA_ORB_init(struct CORBA_ORB_init_args *Args) { ++ int *argc = Args->argc; ++ char **argv = Args->argv; ++ CORBA_ORBid orb_identifier = Args->orb_identifier; ++ CORBA_Environment *ev = Args->ev; ++ ++ int no_iiop_server=0; ++ int no_iiop_proxy=0; ++#ifdef __KORBIT__ ++ int use_ipv4=1; ++#else ++ int use_ipv4=0; ++#endif ++ int use_ipv6=0; ++ int use_usock=1; ++ int debug_level=0; ++ int debug_modules=0; ++ int nosysrc=0; ++ int nouserrc=0; ++ char *imr_ior=NULL, *imr_addr=NULL; ++ char *ir_ior=NULL, *ir_addr=NULL; ++ char *naming_ior=NULL, *naming_addr=NULL; ++ char *root_poa_ior=NULL, *root_poa_addr=NULL; ++ char *orb_id_opt=NULL; ++#ifndef __KORBIT__ ++ char *ctmp; ++#endif ++ CORBA_ORB orb = 0; ++ ++ /* The variable addresses in these structs need to be assigned at ++ * run-time if you want to compile with -pedantic ++ * ++ * (You will also get scads of warnings about "long long" too) ++ */ ++ ++ ORBit_orb_options pre_rc_options[]={ ++ {"ORBNoSystemRC", no_arg, NULL}, ++ {"ORBNoUserRC", no_arg, NULL}, ++ {NULL, 0, NULL}, ++ }; ++ ++ /* These options are compatible with MICO */ ++ ORBit_orb_options options[]={ ++ {"ORBNoIIOPServer", no_arg, NULL}, ++ {"ORBNoIIOPProxy", no_arg, NULL}, ++ {"ORBid", string_arg, NULL}, ++ {"ORBImplRepoIOR", string_arg, NULL}, ++ {"ORBImplRepoAddr", string_arg, NULL}, ++ {"ORBIfaceRepoIOR", string_arg, NULL}, ++ {"ORBIfaceRepoAddr", string_arg, NULL}, ++ {"ORBNamingIOR", string_arg, NULL}, ++ {"ORBNamingAddr", string_arg, NULL}, ++ {"ORBDebugLevel", int_arg, NULL}, ++ {"ORBBindAddr", string_arg, NULL}, /* XXX need to make ++ libIIOP support this */ ++ {"ORBIIOPAddr", string_arg, NULL}, ++ ++ /* These options aren't */ ++ {"ORBDebugModules", int_arg, NULL}, ++ {"ORBRootPOAIOR", string_arg, NULL}, ++ {"ORBRootPOAAddr", string_arg, NULL}, ++ {"ORBIIOPUSock", int_arg, NULL}, ++ {"ORBIIOPIPv4", int_arg, NULL}, ++ {"ORBIIOPIPv6", int_arg, NULL}, ++ {NULL,0,NULL}, ++ }; ++ ++ if (ev == NULL || !argc || !argv || !orb_identifier) { ++ if (ev) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ } ++ up(&StartupSem); // Okay, let the insmod thread continue... ++ return 0; ++ } ++ ++ pre_rc_options[0].arg = (void *) &nosysrc; ++ pre_rc_options[1].arg = (void *) &nouserrc; ++ options[0].arg = (void *) &no_iiop_server; ++ options[1].arg = (void *) &no_iiop_proxy; ++ options[2].arg = (void *) &orb_id_opt; ++ options[3].arg = (void *) &imr_ior; ++ options[4].arg = (void *) &imr_addr; ++ options[5].arg = (void *) &ir_ior; ++ options[6].arg = (void *) &ir_addr; ++ options[7].arg = (void *) &naming_ior; ++ options[8].arg = (void *) &naming_addr; ++ options[9].arg = (void *) &debug_level; ++ options[12].arg = (void *) &debug_modules; ++ options[13].arg = (void *) &root_poa_ior; ++ options[14].arg = (void *) &root_poa_addr; ++ options[15].arg = (void *) &use_usock; ++ options[16].arg = (void *) &use_ipv4; ++ options[17].arg = (void *) &use_ipv6; ++ ++#ifndef __KORBIT__ ++ ORBit_option_parse(argc, argv, pre_rc_options); ++ ++ if(!nosysrc) { ++ ORBit_rc_load(ORBit_SYSRC, options); ++ } ++ ++ if(!nouserrc) { ++ char *buf; ++ ++ ctmp = g_get_home_dir(); ++ ++ buf = alloca(strlen(ctmp) + sizeof("/.orbitrc")); ++ sprintf(buf, "%s/.orbitrc", ctmp); ++ ORBit_rc_load(buf, options); ++ freeca(buf); ++ } ++ ++ ORBit_option_parse(argc, argv, options); ++#endif /* !__KORBIT__ */ ++ ++ ORBit_Trace_setLevel(debug_level); ++ ORBit_Trace_setModules(debug_modules); ++ ++ CORBA_exception_init(ev); ++ ++ ORBit_chunks_init(); ++ ++ giop_init(argv[0]); ++ ++ orb=g_new0(struct CORBA_ORB_type, 1); ++ ++ if(orb==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ goto error; ++ } ++ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(orb), ORBIT_PSEUDO_ORB, ev); ++ ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(orb), ++ (gpointer)&CORBA_ORB_epv, ev); ++ ++ ORBIT_ROOT_OBJECT(orb)->refs = 1; ++ ++ if(orb_id_opt!=NULL) { ++ if(!ORBit_ORBid_setup(orb, orb_id_opt)) ++ goto error; ++ g_free(orb_id_opt); ++ } else if(orb_identifier!=NULL) { ++ if(!ORBit_ORBid_setup(orb, orb_identifier)) ++ goto error; ++ } else { ++ orb->orb_identifier=g_strdup("orbit-local-orb"); ++ } ++ ++ if(orb->orb_identifier==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ goto error; ++ } ++ ++ if(use_ipv4) { ++ orb->cnx.ipv4 = GIOP_CONNECTION(iiop_connection_server()); ++ ++ giop_connection_ref(orb->cnx.ipv4); ++ GIOP_CONNECTION(orb->cnx.ipv4)->orb_data = orb; ++ } ++ ++ if(use_ipv6) { ++ orb->cnx.ipv6 = GIOP_CONNECTION(iiop_connection_server_ipv6()); ++ giop_connection_ref(orb->cnx.ipv6); ++ GIOP_CONNECTION(orb->cnx.ipv6)->orb_data = orb; ++ } ++ ++#ifndef __KORBIT__ ++ if(use_usock) { ++ orb->cnx.usock = ORBit_ORB_make_usock_connection(); ++ ++ giop_connection_ref(orb->cnx.usock); ++ GIOP_CONNECTION(orb->cnx.usock)->orb_data = orb; ++ } ++#endif ++ ++ orb->objrefs = g_hash_table_new((GHashFunc)g_CORBA_Object_hash, ++ (GCompareFunc)g_CORBA_Object_equal); ++ orb->poas = g_ptr_array_new(); ++ ++ /* when I figure out what MICO is doing with the iiop_proxy and ++ * iiop_server stuff, it'll get handled here. ++ */ ++ ++ /* ++ * Connect to / create implementation repository ++ */ ++ ++ { ++ CORBA_Object imr=NULL; ++ ++ if(imr_ior!=NULL) { ++ imr=CORBA_ORB_string_to_object(orb, imr_ior, ev); ++ g_free(imr_ior); ++ } else if(imr_addr!=NULL) { ++ /*imr=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/ImplRepository:1.0", imr_addr, ev);*/ ++ g_free(imr_addr); ++ } ++ ++ if(!CORBA_Object_is_nil(imr, ev)) { ++ CORBA_ORB_set_initial_reference(orb, "ImplementationRepository", imr, ev); ++ } ++ } ++ ++ /* ++ * Connect to / create interface repository ++ */ ++ ++ { ++ CORBA_Object ir=NULL; ++ ++ if(ir_ior!=NULL) { ++ ir=CORBA_ORB_string_to_object(orb, ir_ior, ev); ++ g_free(ir_ior); ++ } else if(ir_addr!=NULL) { ++ /*ir=CORBA_ORB_bind(orb, "IDL:omg.org/CORBA/Repository:1.0", ir_addr, ev);*/ ++ g_free(ir_addr); ++ } ++ ++ if(!CORBA_Object_is_nil(ir, ev)) { ++ CORBA_ORB_set_initial_reference(orb, "InterfaceRepository", ir, ev); ++ } ++ } ++ ++ /* ++ * Connect to naming service ++ */ ++ ++ { ++ CORBA_Object naming=NULL; ++ ++ if(naming_ior!=NULL) { ++ naming=CORBA_ORB_string_to_object(orb, naming_ior, ev); ++ g_free(naming_ior); ++ } else if(naming_addr!=NULL) { ++ /*CORBA_ORB_ObjectTag tag=CORBA_ORB_string_to_tag(orb, "root", ev);*/ ++ ++ /*naming=CORBA_ORB_bind_tag(orb, "IDL:omg.org/CosNaming/NamingContext:1.0", tag, naming_addr, ev);*/ ++ g_free(naming_addr); ++ } ++ ++ if(!CORBA_Object_is_nil(naming, ev)) { ++ CORBA_ORB_set_initial_reference(orb, "NameService", naming, ev); ++ } ++ } ++ ++ /* ++ * Connect to / create RootPOA ++ */ ++ ++ { ++ PortableServer_POA root_poa=CORBA_OBJECT_NIL; ++ ++ if(root_poa_ior!=NULL) { ++ root_poa=(PortableServer_POA) ++ CORBA_ORB_string_to_object(orb, ++ root_poa_ior, ev); ++ g_free(root_poa_ior); ++ } ++ ++ /* And attatch it to the orb */ ++ ++ if(!CORBA_Object_is_nil((CORBA_Object)root_poa, ev)) { ++ CORBA_ORB_set_initial_reference((CORBA_ORB)orb, ++ "RootPOA", ++ (CORBA_Object)root_poa, ++ ev); ++ } ++ } ++ ++ ORBit_custom_run_setup(orb, ev); ++ ++ if (!strcmp("server", argv[0])) // Only do this for servers. ++ TheOneTrueOrb = orb; ++ up(&StartupSem); // Okay, let the insmod thread continue... ++ return orb; ++ ++error: ++ if(orb!=NULL) { ++ ORBit_ORB_release(orb, ev); ++ orb = NULL; ++ } ++ g_free(imr_ior); ++ g_free(imr_addr); ++ g_free(ir_ior); ++ g_free(ir_addr); ++ g_free(naming_ior); ++ g_free(naming_addr); ++ g_free(root_poa_ior); ++ g_free(root_poa_addr); ++ g_free(orb_id_opt); ++ ++ TheOneTrueOrb = 0; ++ up(&StartupSem); // Okay, let the insmod thread continue... ++ return 0; ++} ++ ++ ++#if __KERNEL__ ++#include <linux/smp_lock.h> ++#include <linux/proc_fs.h> ++ ++// This is the main corba thread function... ++// ++void __CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev); ++int MainCORBAThread(void *Args) { ++ // Make a directory in /proc... yaay... ++ proc_mkdir("corba", 0); ++ ++ __CORBA_ORB_init((struct CORBA_ORB_init_args*)Args); ++ if (TheOneTrueOrb == 0) return 0; ++ ++ strcpy(current->comm, "korbit"); // Set the thread name... ++ ++ lock_kernel(); /* This seems to be required for exit_mm */ ++ exit_mm(current); ++ ++ __CORBA_ORB_run(TheOneTrueOrb, ++ ((struct CORBA_ORB_init_args*)Args)->ev); ++ return 0; ++} ++#endif ++ ++ ++/* Section 4.4 ++ * ++ * Adjusts argc and argv appropriately ++ */ ++ ++CORBA_ORB CORBA_ORB_init(int *argc, char **argv, CORBA_ORBid orb_identifier, ++ CORBA_Environment *ev) { ++ ++ struct CORBA_ORB_init_args Args; ++ Args.argc = argc; ++ Args.argv = argv; ++ Args.orb_identifier = orb_identifier; ++ Args.ev = ev; ++ ++#ifdef __KERNEL__ ++ if (!strcmp(argv[0], "server")) { // Are we a server? ++ down(&StartupSem); // Grab the semaphore... ++ if (TheOneTrueOrb) { ++ CORBA_exception_init(ev); ++ goto out_success; ++ } ++ ++ // This releases the semaphore when it is done initializing. ++ (void)kernel_thread(MainCORBAThread, &Args, ++ CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ ++ // This will block until the semaphore is released by the ++ // ORB thread. ++ down(&StartupSem); ++ } else { // If we are a corba client, like CorbaFS... ++ return __CORBA_ORB_init(&Args); ++ } ++ ++ out_success: ++ up(&StartupSem); // Okay, we're now here. ++#else ++ __CORBA_ORB_init(&Args); ++#endif ++ if (TheOneTrueOrb) ++ return (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)TheOneTrueOrb, ev); ++ return 0; ++} ++ ++ ++ ++ ++typedef struct { ++ CORBA_Object obj; ++ CDR_Codec *codec; ++ gboolean emit_active; ++} profile_user_data; ++ ++static void ORBit_emit_profile(gpointer item, gpointer userdata) ++{ ++ ORBit_Object_info *profile=(ORBit_Object_info *)item; ++ profile_user_data *data=(profile_user_data *)userdata; ++ CORBA_Object obj=data->obj; ++ CDR_Codec encaps_codec_d; ++ CDR_Codec *codec=data->codec, *encaps = &encaps_codec_d; ++ gboolean emit_active=data->emit_active; ++ static const CORBA_octet iiopversion[] = {1,0}; ++ CORBA_octet codecbuf[2048]; ++ ++ g_assert(obj!=NULL); ++ g_assert(codec!=NULL); ++ g_assert(profile!=NULL); ++ ++ if((profile == obj->active_profile) && (emit_active == FALSE)) ++ return; /* we already did this one */ ++ ++ switch(profile->profile_type) { ++ case IOP_TAG_INTERNET_IOP: ++ CDR_codec_init_static(encaps); ++ encaps->buffer = codecbuf; ++ encaps->release_buffer = CORBA_FALSE; ++ encaps->buf_len = 2048; ++ encaps->readonly = CORBA_FALSE; ++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS; ++ ++ CDR_put_ulong(codec, IOP_TAG_INTERNET_IOP); ++ CDR_put_octet(encaps, FLAG_ENDIANNESS); ++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion)); ++ CDR_put_string(encaps, profile->tag.iopinfo.host); ++ CDR_put_ushort(encaps, profile->tag.iopinfo.port); ++ CDR_put_ulong(encaps, profile->object_key._length); ++ CDR_put_octets(encaps, profile->object_key._buffer, ++ profile->object_key._length); ++ CDR_put_ulong(codec, encaps->wptr); ++ CDR_put_octets(codec, encaps->buffer, encaps->wptr); ++ break; ++ ++ case IOP_TAG_ORBIT_SPECIFIC: ++ CDR_codec_init_static(encaps); ++ encaps->buffer = codecbuf; ++ encaps->release_buffer = CORBA_FALSE; ++ encaps->buf_len = 2048; ++ encaps->readonly = CORBA_FALSE; ++ encaps->host_endian = encaps->data_endian = FLAG_ENDIANNESS; ++ ++ CDR_put_ulong(codec, IOP_TAG_ORBIT_SPECIFIC); ++ CDR_put_octet(encaps, FLAG_ENDIANNESS); ++ CDR_put_octets(encaps, (gpointer)iiopversion, sizeof(iiopversion)); ++ CDR_put_string(encaps, profile->tag.orbitinfo.unix_sock_path); ++ CDR_put_ushort(encaps, profile->tag.orbitinfo.ipv6_port); ++ CDR_put_ulong(encaps, profile->object_key._length); ++ CDR_put_octets(encaps, profile->object_key._buffer, ++ profile->object_key._length); ++ CDR_put_ulong(codec, encaps->wptr); ++ CDR_put_octets(codec, encaps->buffer, encaps->wptr); ++ break; ++ ++ default: ++ g_warning("Skipping tag %d", profile->profile_type); ++ break; ++ } ++} ++ ++CORBA_char *CORBA_ORB_object_to_string(CORBA_ORB orb, ++ CORBA_Object obj, ++ CORBA_Environment *ev) ++{ ++ int i; ++ CDR_Codec codec_d; ++ CDR_Codec *codec = &codec_d; ++ CORBA_char *rc = NULL; ++ CORBA_unsigned_long ntags; ++ profile_user_data data; ++ CORBA_octet codecbuf[2048]; ++ char *ctmp; ++ ++ g_return_val_if_fail(ev, NULL); ++ o_return_val_if_fail(orb && obj, NULL); ++ ++ if(!obj || !orb) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ if(ORBIT_ROOT_OBJECT(obj)->is_pseudo_object) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ CDR_codec_init_static(codec); ++ ++ codec->buffer = codecbuf; ++ codec->release_buffer = CORBA_FALSE; ++ codec->buf_len = 2048; ++ codec->readonly = CORBA_FALSE; ++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS; ++ ++ CDR_put_octet(codec, FLAG_ENDIANNESS); ++ ++ CDR_put_string(codec, obj->object_id); ++ ntags = g_slist_length(obj->profile_list); ++ CDR_put_ulong(codec, ntags); ++ ++ data.obj=obj; ++ data.codec=codec; ++ data.emit_active=TRUE; ++ if(obj->active_profile != NULL) ++ ORBit_emit_profile(obj->active_profile, &data); /* do this one first */ ++ ++ data.emit_active=FALSE; ++ g_slist_foreach(obj->profile_list, ORBit_emit_profile, &data); ++ ++ rc = CORBA_string_alloc(4 + (codec->wptr * 2) + 1); ++ strcpy(rc, "IOR:"); ++ ++#define hexdigit(n) (((n)>9)?(n+'a'-10):(n+'0')) ++ ++ for(i = 0, ctmp = rc + strlen("IOR:"); i < codec->wptr; i++) { ++ *(ctmp++) = hexdigit((((codec->buffer[i]) & 0xF0) >> 4)); ++ *(ctmp++) = hexdigit(((codec->buffer[i]) & 0xF)); ++ } ++ *ctmp = '\0'; ++ ++ { ++ /* Debug check */ ++ CORBA_Object obj; ++ CORBA_Environment myev; ++ ++ CORBA_exception_init(&myev); ++ ++ obj = CORBA_ORB_string_to_object(orb, rc, &myev); ++ ++ if (CORBA_Object_is_nil(obj, &myev)) { ++ g_warning("Bug in %s, created bad IOR `%s'\n", ++ __FUNCTION__, rc); ++ CORBA_free(rc); ++ return NULL; ++ } ++ ++ CORBA_Object_release(obj, &myev); ++ } ++ ++ return rc; ++} ++ ++/* Quote from the GNU libc manual: ++ ++ "If you try to allocate more storage than the machine can provide, ++ you don't get a clean error message. Instead you get a fatal ++ signal like the one you would get from an infinite recursion; ++ probably a segmentation violation (see section Program Error ++ Signals)." ++ ++ The man page claims alloca() returns NULL on failure; this appears ++ to be a load of shit on Linux where you just get flaming death, but ++ we check anyway in case other systems work that way. ++ ++ On Linux we check that the size is less than MAX_STACK_ALLOC ++ ++ Note that the CORBA_alloc() calls in here can still cause ++ program abort, and really that should be fixed in a similar ++ way since our lengths are coming in from unpredictable sources ++ like files or the network. ++*/ ++ ++#define MAX_STACK_ALLOC 8192 ++ ++CORBA_Object CORBA_ORB_string_to_object(CORBA_ORB orb, CORBA_char *str, ++ CORBA_Environment *ev) ++{ ++ GSList *profiles=NULL; ++ CORBA_Object retval = NULL; ++ CORBA_char *type_id; ++ ORBit_Object_info *object_info; ++ CDR_Codec codec_d, encaps_codec_d; ++ CDR_Codec *codec = &codec_d, *encaps_codec = &encaps_codec_d; ++ CORBA_octet *buffer, endian; ++ int i, j; ++ CORBA_unsigned_long len, seq_len, misclen; ++ ++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL); ++ o_return_val_if_fail(orb && str, CORBA_OBJECT_NIL); ++ ++ if(strncmp(str, "IOR:", 4)) { ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_NO); ++ return(CORBA_OBJECT_NIL); ++ } ++ ++ CDR_codec_init_static(codec); ++ len = strlen(str); ++ ++ if((len % 2) || len <= 4) { ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_NO); ++ return(CORBA_OBJECT_NIL); ++ } ++ ++ codec->buf_len = (len-4)/2; ++ buffer = alloca(codec->buf_len); ++ ++ codec->buffer=buffer; ++ codec->release_buffer = CORBA_FALSE; ++ codec->readonly = TRUE; ++ ++ for(j = 0, i = 4; i < len; i+=2) { ++ buffer[j++] = HEXOCTET(str[i], str[i+1]); ++ }; ++ ++ CDR_get_octet(codec, &endian); ++ ++ codec->data_endian = endian; ++ codec->host_endian = FLAG_ENDIANNESS; ++ ++ CDR_get_string_static(codec, &type_id); ++ ++ CDR_get_seq_begin(codec, &seq_len); ++ ++ for(i = 0; i < seq_len; i++) { ++ IOP_ProfileId tag; ++ ++ object_info=g_new0(ORBit_Object_info, 1); ++ ++ if (!CDR_get_ulong(codec, &tag)) ++ goto error_out; ++ ++ switch(tag) { ++ case IOP_TAG_INTERNET_IOP: ++ if (!CDR_get_ulong(codec, &misclen)) ++ goto error_out; ++ ++ CDR_codec_init_static(encaps_codec); ++ ++ if (misclen > MAX_STACK_ALLOC) ++ goto error_out; ++ ++ encaps_codec->buffer = alloca(misclen); ++ if (encaps_codec->buffer == NULL) ++ /* misclen was probably junk */ ++ goto error_out; ++ ++ encaps_codec->release_buffer = FALSE; ++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen)) ++ goto error_out; ++ ++ encaps_codec->buf_len = misclen; ++ encaps_codec->readonly = CORBA_TRUE; ++ if(!CDR_get_octet(encaps_codec, &endian)) ++ goto error_out; ++ encaps_codec->data_endian = endian; ++ encaps_codec->host_endian = FLAG_ENDIANNESS; ++ ++ if (encaps_codec->data_endian > 1) ++ goto error_out; ++ ++ object_info->profile_type = IOP_TAG_INTERNET_IOP; ++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major)) ++ goto error_out; ++ if(object_info->iiop_major != 1) ++ goto error_out; ++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor)) ++ goto error_out; ++ if(!CDR_get_string(encaps_codec, &object_info->tag.iopinfo.host)) ++ goto error_out; ++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.iopinfo.port)) ++ goto error_out; ++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length)) ++ goto error_out; ++ ++ object_info->object_key._maximum = 0; ++ ++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */ ++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL); ++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer, ++ object_info->object_key._length)) ++ goto error_out; ++ ++ ORBit_set_object_key(object_info); ++ profiles=g_slist_append(profiles, object_info); ++ break; ++ ++ case IOP_TAG_MULTIPLE_COMPONENTS: ++ /* Just skip any multiple_components data, for now */ ++ if(!CDR_get_ulong(codec, &misclen)) ++ goto error_out; ++ ++ CDR_codec_init_static(encaps_codec); ++ ++ if (misclen > MAX_STACK_ALLOC) ++ goto error_out; ++ ++ encaps_codec->buf_len = misclen; ++ encaps_codec->buffer = alloca(misclen); ++ if (encaps_codec->buffer == NULL) ++ /* misclen was probably junk */ ++ goto error_out; ++ ++ encaps_codec->release_buffer = FALSE; ++ encaps_codec->readonly = CORBA_TRUE; ++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen)) ++ goto error_out; ++ break; ++ ++ case IOP_TAG_ORBIT_SPECIFIC: ++ if(!CDR_get_ulong(codec, &misclen)) ++ goto error_out; ++ ++ CDR_codec_init_static(encaps_codec); ++ ++ if (misclen > MAX_STACK_ALLOC) ++ goto error_out; ++ ++ encaps_codec->buffer = alloca(misclen); ++ if (encaps_codec->buffer == NULL) ++ /* misclen was probably junk */ ++ goto error_out; ++ ++ encaps_codec->release_buffer = FALSE; ++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen)) ++ goto error_out; ++ ++ encaps_codec->buf_len = misclen; ++ encaps_codec->readonly = CORBA_TRUE; ++ ++ if(!CDR_get_octet(encaps_codec, &endian)) ++ goto error_out; ++ ++ encaps_codec->data_endian = endian; ++ encaps_codec->host_endian = FLAG_ENDIANNESS; ++ ++ if (encaps_codec->data_endian > 1) ++ goto error_out; ++ ++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC; ++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_major)) ++ goto error_out; ++ ++ if(object_info->iiop_major != 1) ++ goto error_out; ++ if(!CDR_get_octet(encaps_codec, &object_info->iiop_minor)) ++ goto error_out; ++ ++ if(!CDR_get_string(encaps_codec, &object_info->tag.orbitinfo.unix_sock_path)) ++ goto error_out; ++ ++ if(!CDR_get_ushort(encaps_codec, &object_info->tag.orbitinfo.ipv6_port)) ++ goto error_out; ++ if(!CDR_get_seq_begin(encaps_codec, &object_info->object_key._length)) ++ goto error_out; ++ object_info->object_key._maximum = 0; ++ ++ /* The POA gives out ORBit_alloc()d profiles, so we have to too */ ++ object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL); ++ if(!CDR_buffer_gets(encaps_codec, object_info->object_key._buffer, ++ object_info->object_key._length)) ++ goto error_out; ++ ++ ORBit_set_object_key(object_info); ++ profiles=g_slist_append(profiles, object_info); ++ break; ++ default: ++ g_warning("Unknown tag 0x%x", tag); ++ ++ /* Skip it */ ++ if(!CDR_get_ulong(codec, &misclen)) ++ goto error_out; ++ ++ CDR_codec_init_static(encaps_codec); ++ ++ if (misclen > MAX_STACK_ALLOC) ++ goto error_out; ++ ++ encaps_codec->buf_len = misclen; ++ encaps_codec->buffer = alloca(misclen); ++ if (encaps_codec->buffer == NULL) ++ /* misclen was probably junk */ ++ goto error_out; ++ ++ encaps_codec->release_buffer = FALSE; ++ encaps_codec->readonly = CORBA_TRUE; ++ if(!CDR_buffer_gets(codec, encaps_codec->buffer, misclen)) ++ goto error_out; ++ ++ break; ++ } ++ } ++ ++ freeca(buffer); /* Same as codec->buffer */ ++ freeca(encaps_codec->buffer); ++ ++ return ORBit_create_object_with_info(profiles, type_id, orb, ev); ++ ++ error_out: ++ ++ if(object_info) { ++ CORBA_free(object_info->object_key._buffer); ++ g_free(object_info); ++ ORBit_delete_profiles(profiles); ++ } ++ ++ freeca(buffer); /* Same as codec->buffer */ ++ freeca(encaps_codec->buffer); ++ ++ return retval; ++} ++ ++/* Section 4.1.2 */ ++CORBA_boolean CORBA_ORB_get_service_information(CORBA_ORB orb, CORBA_ServiceType service_type, CORBA_ServiceInformation *service_information, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(CORBA_FALSE); ++} ++ ++CORBA_Current *CORBA_ORB_get_current(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, NULL); ++ o_return_val_if_fail(orb, NULL); ++ ++ /* XXX check this over */ ++ return (CORBA_Current *)GET_THREAD_DATA(); ++} ++ ++/* Section 4.5 */ ++CORBA_ORB_ObjectIdList *CORBA_ORB_list_initial_services(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ static const char *services[] = {"RootPOA"}; ++ CORBA_ORB_ObjectIdList *list; ++ ++ g_return_val_if_fail(ev, NULL); ++ o_return_val_if_fail(orb, NULL); ++ ++ list = (CORBA_ORB_ObjectIdList *)CORBA_sequence_octet__alloc(); ++ list->_maximum=list->_length= 1; ++ list->_buffer = (CORBA_ORB_ObjectId *)services; ++ CORBA_sequence_set_release((void *)list, CORBA_FALSE); ++ ++ /* defined reserved references are: ++ * RootPOA ++ * POACurrent ++ * InterfaceRepository ++ * NameService ++ * TradingService ++ * SecurityCurrent ++ * TransactionCurrent ++ */ ++ ++ return list; ++} ++ ++/* Section 4.5 ++ * ++ * raises InvalidName ++ */ ++CORBA_Object CORBA_ORB_resolve_initial_references(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL); ++ o_return_val_if_fail(orb, CORBA_OBJECT_NIL); ++ ++ if(!strcmp(identifier, "ImplementationRepository")) ++ return CORBA_Object_duplicate(orb->imr, ev); ++ else if(!strcmp(identifier, "InterfaceRepository")) ++ return CORBA_Object_duplicate(orb->ir, ev); ++ else if(!strcmp(identifier, "NameService")) ++ return CORBA_Object_duplicate(orb->naming, ev); ++ else if(!strcmp(identifier, "RootPOA")) { ++ if(CORBA_Object_is_nil(orb->root_poa, ev)) { ++ CORBA_PolicyList policies = {0,0,NULL,CORBA_FALSE}; ++ PortableServer_POAManager poa_mgr; ++ /* Create a poa manager */ ++ poa_mgr = ORBit_POAManager_new(ev); ++ poa_mgr->orb = orb; ++ ++ /* Create the root poa */ ++ orb->root_poa = (CORBA_Object) ++ ORBit_POA_new(orb, ++ "RootPOA", ++ poa_mgr, ++ &policies, ++ ev); ++ CORBA_Object_duplicate(orb->root_poa, ev); ++ } ++ ++ return CORBA_Object_duplicate(orb->root_poa, ev); ++ } ++ ++ /* throw user exception: InvalidName */ ++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION, ++ ex_CORBA_ORB_InvalidName, ++ NULL); ++ ++ goto error; ++error: ++ return(NULL); ++} ++ ++/* This is a MICO extension ++ * ++ * raises InvalidName ++ */ ++void CORBA_ORB_set_initial_reference(CORBA_ORB orb, CORBA_ORB_ObjectId identifier, CORBA_Object obj, CORBA_Environment *ev) ++{ ++ g_return_if_fail(ev); ++ o_return_if_fail(orb && identifier && obj); ++ ++ if(!strcmp(identifier, "ImplementationRepository")) { ++ if(!CORBA_Object_is_nil(orb->imr, ev)) { ++ CORBA_Object_release(orb->imr, ev); ++ } ++ orb->imr=CORBA_Object_duplicate(obj, ev); ++ } else if(!strcmp(identifier, "InterfaceRepository")) { ++ if(!CORBA_Object_is_nil(orb->ir, ev)) { ++ CORBA_Object_release(orb->ir, ev); ++ } ++ orb->ir=CORBA_Object_duplicate(obj, ev); ++ } else if(!strcmp(identifier, "NameService")) { ++ if(!CORBA_Object_is_nil(orb->naming, ev)) { ++ CORBA_Object_release(orb->naming, ev); ++ } ++ orb->naming=CORBA_Object_duplicate(obj, ev); ++ } else if(!strcmp(identifier, "RootPOA")) { ++ if(!CORBA_Object_is_nil(orb->root_poa, ev)) { ++ CORBA_Object_release(orb->root_poa, ev); ++ } ++ orb->root_poa=CORBA_Object_duplicate(obj, ev); ++ } else { ++ /* throw user exception: InvalidName */ ++ CORBA_exception_set(ev,CORBA_USER_EXCEPTION,ex_CORBA_ORB_InvalidName,NULL); ++ goto error; ++ } ++ ++ return; ++error: ++ return; ++} ++ ++/* Section 4.9.1 */ ++CORBA_boolean CORBA_ORB_work_pending(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(CORBA_FALSE); ++} ++ ++/* Section 4.9.2 */ ++void CORBA_ORB_perform_work(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return; ++} ++ ++/* Section 4.9.4 */ ++void ++CORBA_ORB_shutdown(CORBA_ORB orb, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev) ++{ ++ g_return_if_fail(ev); ++ o_return_if_fail(orb); ++ ++ /* XXX implement on a per-ORB basis, and also ++ handle whatever wait_for_completion means */ ++ ++ if(orb->cnx.ipv4) ++ giop_connection_unref(orb->cnx.ipv4); ++ if(orb->cnx.ipv6) ++ giop_connection_unref(orb->cnx.ipv6); ++#ifndef __KORBIT__ ++ if(orb->cnx.usock) ++ giop_connection_unref(orb->cnx.usock); ++#endif ++ ++ giop_main_quit(); ++} ++ ++/* Section 4.9.3 */ ++/* CORBA_ORB_run is in server.c */ ++ ++/* Section 4.7 */ ++CORBA_PolicyType ++CORBA_Policy__get_policy_type(CORBA_Policy obj, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, 0); ++ o_return_val_if_fail(obj, 0); ++ ++ return obj->policy_type; ++} ++ ++/* Section 4.7 */ ++CORBA_Policy CORBA_Policy_copy(CORBA_Policy obj, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL); ++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL); ++ ++ ORBIT_ROOT_OBJECT_REF(obj); ++ ++ return obj; ++} ++ ++/* Section 4.7 ++ * ++ * raises CORBA_NO_PERMISSION ++ */ ++void CORBA_Policy_destroy(CORBA_Policy obj, CORBA_Environment *ev) ++{ ++ g_return_if_fail(ev); ++ o_return_if_fail(obj); ++ ++ ORBIT_ROOT_OBJECT_UNREF(obj); ++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) ++ ORBIT_ROOT_OBJECT_release(obj, ev); ++} ++ ++#ifndef __KORBIT__ ++/* Section 4.8.2 */ ++CORBA_Policy CORBA_DomainManager_get_domain_policy(CORBA_DomainManager obj, CORBA_PolicyType policy_type, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, CORBA_OBJECT_NIL); ++ o_return_val_if_fail(obj, CORBA_OBJECT_NIL); ++ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++/* Section 4.8.2 */ ++void CORBA_ConstructionPolicy_make_domain_manager(CORBA_ConstructionPolicy obj, CORBA_InterfaceDef object_type, CORBA_boolean constr_policy, CORBA_Environment * ++ev) ++{ ++ g_return_if_fail(ev); ++ o_return_if_fail(obj && object_type); ++ ++ g_assert(!"Not yet implemented"); ++ return; ++} ++ ++/* Section 4.2.8 */ ++CORBA_DomainManagerList *CORBA_Object_get_domain_managers(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(ev, NULL); ++ o_return_val_if_fail(obj, NULL); ++ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ int i; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc == NULL) ++ goto tc_alloc_failed; ++ ++ tc->subtypes=g_new0(CORBA_TypeCode, members._length); ++ if(tc->subtypes == NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->subnames=g_new0(char *, members._length); ++ if(tc->subnames == NULL) ++ goto subnames_alloc_failed; ++ ++ tc->kind=CORBA_tk_struct; ++ tc->name=g_strdup(name); ++ tc->repo_id=g_strdup(id); ++ tc->sub_parts=members._length; ++ tc->length=members._length; ++ ++ for(i=0;i<members._length;i++) { ++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]); ++ ++ g_assert(&(mem->type)!=NULL); ++ ++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct)); ++ tc->subnames[i]=g_strdup(mem->name); ++ } ++ ++ return(tc); ++ ++ subnames_alloc_failed: ++ g_free(tc->subtypes); ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return NULL; ++} ++ ++CORBA_TypeCode ++CORBA_ORB_create_union_tc(CORBA_ORB obj, CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_TypeCode discriminator_type, ++ CORBA_UnionMemberSeq members, ++ CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ int i; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ ++ if(tc == NULL) ++ goto tc_alloc_failed; ++ ++ tc->discriminator = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ ++ if(tc->discriminator == NULL) ++ goto discriminator_alloc_failed; ++ ++ memcpy(tc->discriminator, discriminator_type, (size_t)sizeof(CORBA_TypeCode)); ++ ++ tc->subtypes=g_new0(CORBA_TypeCode, members._length); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->subnames=g_new0(char *, members._length); ++ if(tc->subnames==NULL) ++ goto subnames_alloc_failed; ++ ++ tc->sublabels=g_new0(CORBA_any, members._length); ++ if(tc->sublabels == NULL) ++ goto sublabels_alloc_failed; ++ ++ tc->kind=CORBA_tk_union; ++ tc->name=g_strdup(name); ++ tc->repo_id=g_strdup(id); ++ tc->sub_parts=members._length; ++ tc->length=members._length; ++ tc->default_index=-1; ++ ++ for(i=0;i<members._length;i++) { ++ CORBA_UnionMember *mem=(CORBA_UnionMember *)&(members._buffer[i]); ++ ++ g_assert(&(mem->label)!=NULL); ++ memcpy(&(tc->sublabels[i]), &(mem->label), (size_t)sizeof(CORBA_any)); ++ g_assert(&(mem->type)!=NULL); ++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct)); ++ tc->subnames[i]=g_strdup(mem->name); ++ ++ if(mem->label._type->kind==CORBA_tk_octet) { ++ tc->default_index=i; ++ } ++ } ++ ++ return(tc); ++ ++sublabels_alloc_failed: ++ g_free(tc->sublabels); ++subnames_alloc_failed: ++ g_free(tc->subtypes); ++subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc->discriminator); ++discriminator_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return NULL; ++} ++ ++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_EnumMemberSeq members, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ int i; ++ ++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc == NULL) ++ goto tc_alloc_failed; ++ ++ tc->subnames=g_new0(char *, members._length); ++ if(tc->subnames==NULL) ++ goto subnames_alloc_failed; ++ ++ tc->kind = CORBA_tk_enum; ++ tc->name = g_strdup(name); ++ tc->repo_id = g_strdup(id); ++ tc->sub_parts = members._length; ++ tc->length = members._length; ++ ++ for(i=0;i<members._length;i++) { ++ tc->subnames[i]=g_strdup(members._buffer[i]); ++ } ++ ++ return(tc); ++ ++ subnames_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_TypeCode original_type, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) ++ goto tc_alloc_failed; ++ ++ /* Can't use chunks here, because it's sometimes an array. Doh! */ ++ tc->subtypes=g_new0(CORBA_TypeCode, 1); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->kind=CORBA_tk_alias; ++ tc->name=g_strdup(name); ++ tc->repo_id=g_strdup(id); ++ tc->sub_parts=1; ++ tc->length=1; ++ ++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[0], original_type, (size_t)sizeof(struct CORBA_TypeCode_struct)); ++ ++ return(tc); ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return NULL; ++} ++ ++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_StructMemberSeq members, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ int i; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) ++ goto tc_alloc_failed; ++ ++ tc->subtypes=g_new0(CORBA_TypeCode, members._length); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->subnames=g_new0(char *, members._length); ++ if(tc->subnames==NULL) ++ goto subnames_alloc_failed; ++ ++ tc->kind=CORBA_tk_except; ++ tc->name=g_strdup(name); ++ tc->repo_id=g_strdup(id); ++ tc->sub_parts=members._length; ++ tc->length=members._length; ++ ++ for(i=0;i<members._length;i++) { ++ CORBA_StructMember *mem=(CORBA_StructMember *)&(members._buffer[i]); ++ ++ g_assert(mem->type != NULL); ++ tc->subtypes[i] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[i], mem->type, (size_t)sizeof(struct CORBA_TypeCode_struct)); ++ tc->subnames[i]=g_strdup(mem->name); ++ } ++ ++ return(tc); ++ ++ subnames_alloc_failed: ++ g_free(tc->subtypes); ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj, CORBA_RepositoryId id, CORBA_Identifier name, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, ++ CORBA_COMPLETED_NO); ++ return(NULL); ++ } ++ ++ tc->kind=CORBA_tk_objref; ++ tc->name=g_strdup(name); ++ tc->repo_id=g_strdup(id); ++ ++ return(tc); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++ } ++ ++ tc->kind=CORBA_tk_string; ++ tc->length=bound; ++ ++ return(tc); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++ } ++ ++ tc->kind=CORBA_tk_wstring; ++ tc->length=bound; ++ ++ return(tc); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj, CORBA_unsigned_short digits, CORBA_short scale, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++ } ++ ++ tc->kind=CORBA_tk_fixed; ++ tc->digits=digits; ++ tc->scale=scale; ++ ++ return(tc); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_TypeCode element_type, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) ++ goto tc_alloc_failed; ++ ++ /* Can't use chunks here because we can only be sure of getting ++ one consecutive chunk from glib */ ++ tc->subtypes=g_new0(CORBA_TypeCode, 1); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->kind=CORBA_tk_sequence; ++ tc->sub_parts=1; ++ tc->length=bound; ++ ++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[0], element_type, ++ (size_t)sizeof(struct CORBA_TypeCode_struct)); ++ ++ return(tc); ++ ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc(CORBA_ORB obj, CORBA_unsigned_long bound, CORBA_unsigned_long offset, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) ++ goto tc_alloc_failed; ++ ++ tc->subtypes=g_new0(CORBA_TypeCode, 1); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->kind=CORBA_tk_sequence; ++ tc->sub_parts=1; ++ tc->length=bound; ++ ++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ tc->subtypes[0]->kind=CORBA_tk_recursive; ++ tc->subtypes[0]->recurse_depth=offset; ++ ++ return(tc); ++ ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++} ++ ++CORBA_TypeCode CORBA_ORB_create_array_tc(CORBA_ORB obj, CORBA_unsigned_long length, CORBA_TypeCode element_type, CORBA_Environment *ev) ++{ ++ CORBA_TypeCode tc; ++ ++ tc=ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ if(tc==NULL) ++ goto tc_alloc_failed; ++ ++ tc->subtypes=g_new0(CORBA_TypeCode, 1); ++ if(tc->subtypes==NULL) ++ goto subtypes_alloc_failed; ++ ++ tc->kind=CORBA_tk_array; ++ tc->sub_parts=1; ++ tc->length=length; ++ ++ tc->subtypes[0] = ORBIT_CHUNK_ALLOC(CORBA_TypeCode); ++ memcpy(tc->subtypes[0], element_type, (size_t)sizeof(CORBA_TypeCode)); ++ ++ return(tc); ++ ++ subtypes_alloc_failed: ++ ORBIT_CHUNK_FREE(CORBA_TypeCode, tc); ++ tc_alloc_failed: ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ return(NULL); ++} ++#endif /* !__KORBIT__ */ +diff -urN linux-2.4.1/net/korbit/orb/orb.h linux-2.4.1-korbit/net/korbit/orb/orb.h +--- linux-2.4.1/net/korbit/orb/orb.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orb.h Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,231 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_ORB_H_ ++#define _ORBIT_ORB_H_ ++ ++#include "orb/orbit_types.h" ++#ifndef __KORBIT__ ++#include "orb/interface_repository.h" ++#endif /* !__KORBIT__ */ ++ ++extern CORBA_ORB CORBA_ORB_init( ++ int *argc, ++ char **argv, ++ CORBA_ORBid orb_identifier, ++ CORBA_Environment *ev); ++ ++extern CORBA_char *CORBA_ORB_object_to_string( ++ CORBA_ORB orb, ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object CORBA_ORB_string_to_object( ++ CORBA_ORB orb, ++ CORBA_char *str, ++ CORBA_Environment *ev); ++ ++extern CORBA_Status CORBA_ORB_get_default_context( ++ CORBA_ORB orb, ++ CORBA_Context *ctx, ++ CORBA_Environment *ev); ++ ++extern CORBA_boolean CORBA_ORB_get_service_information( ++ CORBA_ORB orb, ++ CORBA_ServiceType service_type, ++ CORBA_ServiceInformation *service_information, ++ CORBA_Environment *ev); ++ ++extern CORBA_Current *CORBA_ORB_get_current( ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++extern CORBA_ORB_ObjectIdList* CORBA_ORB_list_initial_services( ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object CORBA_ORB_resolve_initial_references( ++ CORBA_ORB orb, ++ CORBA_ORB_ObjectId identifier, ++ CORBA_Environment *ev); ++ ++extern void CORBA_ORB_set_initial_reference( ++ CORBA_ORB orb, ++ CORBA_ORB_ObjectId identifier, ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_boolean CORBA_ORB_work_pending( ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++extern void CORBA_ORB_perform_work( ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++extern void CORBA_ORB_shutdown( ++ CORBA_ORB orb, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev); ++ ++extern void CORBA_ORB_run( ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++extern CORBA_PolicyType CORBA_Policy__get_policy_type( ++ CORBA_Policy obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Policy CORBA_Policy_copy( ++ CORBA_Policy obj, ++ CORBA_Environment *ev); ++ ++extern void CORBA_Policy_destroy( ++ CORBA_Policy obj, ++ CORBA_Environment *ev); ++ ++#ifndef __KORBIT__ ++extern CORBA_InterfaceDef CORBA_Object_get_interface( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++#endif /* !__KORBIT__ */ ++ ++extern CORBA_boolean CORBA_Object_is_nil( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object CORBA_Object_duplicate( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern void CORBA_Object_release( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_boolean CORBA_Object_non_existent( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_boolean CORBA_Object_is_equivalent( ++ CORBA_Object obj, ++ CORBA_Object other_object, ++ CORBA_Environment *ev); ++ ++extern CORBA_unsigned_long CORBA_Object_hash( ++ CORBA_Object obj, ++ CORBA_unsigned_long maximum, ++ CORBA_Environment *ev); ++ ++extern CORBA_Policy CORBA_Object_get_policy( ++ CORBA_Object obj, ++ CORBA_PolicyType policy_type, ++ CORBA_Environment *ev); ++ ++#ifndef __KORBIT__ ++extern CORBA_DomainManagerList *CORBA_Object_get_domain_managers( ++ CORBA_Object obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_Policy CORBA_DomainManager_get_domain_policy( ++ CORBA_DomainManager obj, ++ CORBA_PolicyType policy_type, ++ CORBA_Environment *ev); ++ ++extern void CORBA_ConstructionPolicy_make_domain_manager( ++ CORBA_ConstructionPolicy obj, ++ CORBA_Object /*CORBA_InterfaceDef*/ object_type, ++ CORBA_boolean constr_policy, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_struct_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_StructMemberSeq members, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_union_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_TypeCode discriminator_type, ++ CORBA_UnionMemberSeq members, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_enum_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_EnumMemberSeq members, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_alias_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_TypeCode original_type, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_exception_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_StructMemberSeq members, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_interface_tc(CORBA_ORB obj, ++ CORBA_RepositoryId id, ++ CORBA_Identifier name, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_string_tc(CORBA_ORB obj, ++ CORBA_unsigned_long bound, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_wstring_tc(CORBA_ORB obj, ++ CORBA_unsigned_long bound, ++ CORBA_Environment *ev); ++ ++CORBA_TypeCode CORBA_ORB_create_fixed_tc(CORBA_ORB obj, ++ CORBA_unsigned_short digits, ++ CORBA_short scale, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_ORB_create_sequence_tc( ++ CORBA_ORB obj, ++ CORBA_unsigned_long bound, ++ CORBA_TypeCode element_type, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_ORB_create_recursive_sequence_tc( ++ CORBA_ORB obj, ++ CORBA_unsigned_long bound, ++ CORBA_unsigned_long offset, ++ CORBA_Environment *ev); ++ ++extern CORBA_TypeCode CORBA_ORB_create_array_tc( ++ CORBA_ORB obj, ++ CORBA_unsigned_long length, ++ CORBA_TypeCode element_type, ++ CORBA_Environment *ev); ++ ++#endif /* !__KORBIT__ */ ++ ++#endif /* !_ORBIT_ORB_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit.c linux-2.4.1-korbit/net/korbit/orb/orbit.c +--- linux-2.4.1/net/korbit/orb/orbit.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit.c Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,387 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++/* ++ * This file is a repository for random functions that don't fit anywhere ++ * else, and for ORBit-specific stuff. ++ */ ++ ++#include <stdlib.h> ++#include <string.h> ++#include <sys/types.h> ++#include <netdb.h> ++#include <netinet/in.h> ++#include <arpa/inet.h> ++#include <assert.h> ++#include <math.h> ++ ++#include "orbit.h" ++ ++const guint orbit_major_version = ORBIT_MAJOR_VERSION, ++ orbit_minor_version = ORBIT_MINOR_VERSION, ++ orbit_micro_version = ORBIT_MICRO_VERSION; ++const char orbit_version[] = ORBIT_VERSION; ++ ++typedef struct ORBitClassInfo ORBitClassInfo; ++ ++typedef void (*ORBitObjectInitFunc)(CORBA_Object _handle_to_be, gpointer class_data); ++ ++struct ORBitClassInfo { ++ char *name; ++ gulong id; ++ gpointer method_stubs, method_skels; ++ ORBitObjectInitFunc class_vtable_init_func; ++ ORBitClassInfo **parent_classes; ++}; ++ ++GHashTable *orbit_class_list = NULL, *orbit_class_byid; ++glong class_id_counter = -1; ++ ++void CORBA_any_set_release(CORBA_any *any, CORBA_boolean flag) ++{ ++ g_assert(any!=NULL); ++ ++ if(flag==CORBA_TRUE) { ++ any->_release |= CORBA_ANYFLAGS_RELEASE; ++ } else { ++ any->_release &= ~CORBA_ANYFLAGS_RELEASE; ++ } ++ ++} ++ ++CORBA_boolean CORBA_any_get_release(CORBA_any *any) ++{ ++ g_assert(any!=NULL); ++ ++ if(any->_release & CORBA_ANYFLAGS_RELEASE) ++ return(CORBA_TRUE); ++ else ++ return(CORBA_FALSE); ++} ++ ++void CORBA_sequence_set_release(void *seq, CORBA_boolean flag) ++{ ++ struct CORBA_Sequence_type *sequence; ++ ++ g_assert(seq!=NULL); ++ ++ sequence=(struct CORBA_Sequence_type *)seq; ++ ++ if(flag==CORBA_TRUE) { ++ sequence->_release |= CORBA_ANYFLAGS_RELEASE; ++ } else { ++ sequence->_release &= ~CORBA_ANYFLAGS_RELEASE; ++ } ++} ++ ++CORBA_boolean CORBA_sequence_get_release(void *seq) ++{ ++ struct CORBA_Sequence_type *sequence; ++ ++ g_assert(seq!=NULL); ++ ++ sequence=(struct CORBA_Sequence_type *)seq; ++ ++ if(sequence->_release & CORBA_ANYFLAGS_RELEASE) ++ return(CORBA_TRUE); ++ else ++ return(CORBA_FALSE); ++} ++ ++/* ++ * As far as I understand, values returned by CORBA_*_alloc() are supposed to be ++ * freeable by CORBA_free(), so we can't use memory chunks here in any reasonable ++ * fashion. ++ */ ++gpointer ++CORBA_any__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings) ++{ ++ CORBA_any *aval = mem; ++ ++ if(aval->_release) ++ ORBit_free(aval->_value, free_strings); ++ CORBA_Object_release((CORBA_Object)aval->_type, NULL); ++ ++ return aval + 1; ++} ++ ++CORBA_any *CORBA_any_alloc(void) ++{ ++ CORBA_any *retval = ORBit_alloc(sizeof(CORBA_any), &CORBA_any__free, ++ GINT_TO_POINTER(1)); ++ ++ memset(retval, 0, sizeof(CORBA_any)); /* Make things easier on stubs */ ++ ++ return retval; ++} ++ ++/* ++ * Compares the typecodes of each any ++ */ ++CORBA_boolean ORBit_any_equivalent(CORBA_any obj, CORBA_any any, CORBA_Environment *ev) ++{ ++ return(CORBA_FALSE); ++} ++ ++/* This is needed by skels, that generate a __free function when they see ++ the TypeCode interface */ ++gpointer ++CORBA_TypeCode__free(gpointer mem, gpointer func_data, CORBA_boolean free_strings) ++{ ++ CORBA_Object_release(*(CORBA_Object *)mem, NULL); ++ return ((guchar *)mem) + sizeof(CORBA_TypeCode); ++} ++ ++CORBA_char *CORBA_string_dup(const CORBA_char *string) ++{ ++ if(!string) ++ return NULL; ++ ++ return strcpy(ORBit_alloc(strlen(string)+1, NULL, NULL), string); ++} ++ ++CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len) ++{ ++ return ORBit_alloc(len + 1, NULL, NULL); ++} ++ ++CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len) ++{ ++ return ORBit_alloc(len + 1, NULL, NULL); ++} ++ ++gpointer ++CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings) ++{ ++ if(free_strings) ++ CORBA_free(*((gpointer *)str)); ++ return (gpointer)((guchar *)str + sizeof(CORBA_char *)); ++} ++ ++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings) ++{ ++ CORBA_Environment ev; ++ CORBA_exception_init(&ev); ++ CORBA_Object_release(*((gpointer *)str), &ev); ++ CORBA_exception_free(&ev); ++ return (gpointer)((guchar *)str + sizeof(CORBA_Object)); ++} ++ ++/* 19.14 */ ++ ++/* The big picture for fixeds. ++ We have to represent a number in memory. ++ ++ 1 2 3 . 4 5 6 7 ++ ++ There are three pieces of information in a fixed: ++ ++ - Number of significant digits. (_digits) ++ ++ - The scale. The number of places the decimal point is to the right ++ of the first significant digit. (_scale) ++ ++ - The digits themselves (_value) ++ ++ */ ++CORBA_long CORBA_fixed_integer_part(const void *fp) ++{ ++ CORBA_long retval = 0; ++ int i, power_of_ten, digit; ++ const CORBA_fixed_d_s *val = fp; ++ ++ g_return_val_if_fail(fp != NULL, INT_MIN); ++ ++ for(i = 0; i < (val->_digits - val->_scale); i++) { ++ power_of_ten = val->_digits - i - val->_scale - 1; ++ digit = val->_value[i]; ++ retval += digit * ((int)pow(10, power_of_ten)); ++ } ++ ++ return retval; ++} ++ ++CORBA_long CORBA_fixed_fraction_part(const void *fp) ++{ ++ CORBA_long retval = 0; ++ int i, power_of_ten, digit; ++ const CORBA_fixed_d_s *val = fp; ++ ++ g_return_val_if_fail(fp != NULL, INT_MIN); ++ ++ for(i = val->_digits - val->_scale; i < val->_digits; i++){ ++ power_of_ten = val->_digits - i - 1; ++ digit = val->_value[i]; ++ retval += digit * ((int)pow(10, power_of_ten)); ++ } ++ ++ return retval; ++} ++ ++static inline ++CORBA_long do_div (CORBA_long *n) ++{ ++ int __res; ++ ++ __res = (*n) % (unsigned) 10; ++ *n = (*n) / (unsigned) 10; ++ ++ return __res; ++} ++ ++void CORBA_fixed_set(void *rp, CORBA_long i, CORBA_long f) ++{ ++ CORBA_fixed_d_s *val = rp; ++ CORBA_long left_to_eat, cur; ++ signed char sign = 1; ++ ++ g_return_if_fail(rp != NULL); ++ ++ memset(val->_value, 0, val->_digits); ++ ++ if(i) sign = i/abs(i); ++ val->_sign = sign; ++ i = abs(i); ++ f = abs(f); ++ ++ for(cur = 0, left_to_eat = i; ++ left_to_eat != 0 && cur < val->_digits; cur++) { ++ val->_value[cur] = do_div(&left_to_eat) * sign; ++ sign = 1; ++ } ++ ++ val->_scale = cur - 1; ++ ++ for(left_to_eat = f; ++ left_to_eat != 0 && cur < val->_digits; cur++) { ++ val->_value[cur] = do_div(&left_to_eat); ++ } ++} ++ ++void CORBA_fixed_add(void *rp, const void *f1p, const void *f2p) ++{ ++ g_assert(!"Not yet implemented"); ++} ++ ++void CORBA_fixed_sub(void *rp, const void *f1p, const void *f2p) ++{ ++ g_assert(!"Not yet implemented"); ++} ++ ++void CORBA_fixed_mul(void *rp, const void *f1p, const void *f2p) ++{ ++ g_assert(!"Not yet implemented"); ++} ++ ++void CORBA_fixed_div(void *rp, const void *f1p, const void *f2p) ++{ ++ g_assert(!"Not yet implemented"); ++} ++ ++CORBA_fixed_d_s *CORBA_fixed_alloc(CORBA_unsigned_short d) ++{ ++ return (CORBA_fixed_d_s *) ++ g_malloc(sizeof(CORBA_fixed_d_s) + d + 1); ++} ++ ++void CORBA_free(void *storage) ++{ ++ ORBit_free(storage, CORBA_TRUE); ++} ++ ++int ORBit_parse_unixsock(CORBA_Object obj, ++ char *sockpath, ++ gboolean existing_only) ++{ ++ if(!sockpath || !*sockpath) ++ return -1; ++ ++ obj->connection = ++ GIOP_CONNECTION(iiop_connection_unix_get(sockpath, ++ existing_only)); ++ ++ if(!obj->connection) ++ return -1; ++ ++ giop_connection_ref(obj->connection); ++ return 0; ++} ++ ++int ORBit_parse_inet(CORBA_Object obj, char *hostname, unsigned short port, ++ gboolean existing_only) ++{ ++ obj->connection = GIOP_CONNECTION(iiop_connection_get(hostname, port, existing_only)); ++ ++ if(!obj->connection) ++ return -1; ++ giop_connection_ref(obj->connection); ++ return 0; ++} ++ ++static const CORBA_unsigned_long zero_int = 0; ++struct iovec ORBit_default_principal_iovec = {(gpointer)&zero_int, sizeof(zero_int)}; ++ ++void ORBit_set_default_principal(CORBA_Principal *principal) ++{ ++ gpointer t; ++ ++ if((gpointer)ORBit_default_principal_iovec.iov_base != (gpointer)&zero_int) ++ g_free(ORBit_default_principal_iovec.iov_base); ++ ++ ORBit_default_principal_iovec.iov_len = principal->_length ++ + sizeof(CORBA_unsigned_long); ++ ++ t = ORBit_default_principal_iovec.iov_base = ++ g_malloc(ORBit_default_principal_iovec.iov_len); ++ ++ memcpy(t, &principal->_length, sizeof(principal->_length)); ++ ++ t = ((guchar *)t) + sizeof(principal->_length); ++ memcpy(t, principal->_buffer, principal->_length); ++} ++ ++CORBA_unsigned_long ORBit_class_assignment_counter = 0; ++GHashTable *ORBit_class_assignments = NULL; ++ ++/* XXX not thread-safe */ ++CORBA_unsigned_long ++ORBit_register_class(const PortableServer_ClassInfo *class_info) ++{ ++ CORBA_unsigned_long retval; ++ ++ if(!ORBit_class_assignments) ++ ORBit_class_assignments = g_hash_table_new(g_str_hash, g_str_equal); ++ ++ /* This needs to be pre-increment - we don't want to give out ++ classid 0, because (a) that is reserved for the base Object class ++ (b) all the routines allocate a new id if the variable ++ storing their ID == 0 */ ++ retval = ++ORBit_class_assignment_counter; ++ ++ g_hash_table_insert(ORBit_class_assignments, (gpointer)class_info->class_name, ++ GINT_TO_POINTER(retval)); ++ ++ return retval; ++} +diff -urN linux-2.4.1/net/korbit/orb/orbit.h linux-2.4.1-korbit/net/korbit/orb/orbit.h +--- linux-2.4.1/net/korbit/orb/orbit.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,207 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++/* these two blocks are outside of the main header for good reason... ++ People may include headers from many different stubs, and we want to ++ have the version checked on all of them. ++ */ ++#ifndef ORBIT_SERIAL ++#define ORBIT_SERIAL 9 ++#endif ++ ++#ifdef ORBIT_IDL_SERIAL ++#if ORBIT_IDL_SERIAL < 9 ++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated." ++#endif ++#endif ++ ++#ifndef _ORBIT_H_ ++#define _ORBIT_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#include <glib.h> ++ ++#define BACKWARDS_COMPAT_0_4 ++#undef NOT_BACKWARDS_COMPAT_0_4 ++ ++#include <sys/types.h> ++#include <sys/uio.h> ++#include <IIOP/IIOP.h> ++#include <ORBitutil/util.h> ++#include <orb/orbit_config.h> ++#include <orb/orbit_types.h> ++#include <orb/allocators.h> ++#include <orb/cdr.h> ++#include <orb/dii.h> ++#ifndef __KORBIT__ ++#include <orb/dynany.h> ++#endif ++#include <orb/env.h> ++#include <orb/iop.h> ++#include <orb/ir.h> ++#include <orb/options.h> ++#include <orb/orb.h> ++#include <orb/poa.h> ++#include <orb/sequences.h> ++#include <orb/orbit_typecode.h> ++#include <orb/typecode.h> ++ ++#ifndef ORBIT_MAJOR_VERSION ++#define ORBIT_MAJOR_VERSION (0) ++#define ORBIT_MINOR_VERSION (5) ++#define ORBIT_MICRO_VERSION (3) ++#endif ++ ++extern const guint orbit_major_version, ++ orbit_minor_version, ++ orbit_micro_version; ++extern const char orbit_version[]; ++ ++extern void CORBA_any_set_release( ++ CORBA_any *, ++ CORBA_boolean); ++ ++extern CORBA_boolean CORBA_any_get_release( ++ CORBA_any *); ++ ++extern void CORBA_sequence_set_release( ++ void *, ++ CORBA_boolean); ++ ++extern CORBA_boolean CORBA_sequence_get_release( ++ void *); ++ ++#define CORBA_any__alloc CORBA_any_alloc ++extern CORBA_any *CORBA_any_alloc( ++ void); ++ ++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data, ++ CORBA_boolean free_strings); ++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data, ++ CORBA_boolean free_strings); ++ ++extern CORBA_boolean ORBit_any_equivalent( ++ CORBA_any obj, ++ CORBA_any any, ++ CORBA_Environment *ev); ++ ++extern CORBA_char *CORBA_string_dup(const CORBA_char *string); ++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len); ++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings); ++ ++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings); ++ ++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len); ++#define CORBA_wstring_free CORBA_string_free ++ ++/* 19.14 */ ++extern CORBA_long CORBA_fixed_integer_part( ++ const void *fp); ++ ++extern CORBA_long CORBA_fixed_fraction_part( ++ const void *fp); ++ ++extern void CORBA_fixed_set( ++ void *rp, ++ CORBA_long i, ++ CORBA_long f); ++ ++extern void CORBA_fixed_add( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_sub( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_mul( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_div( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern CORBA_fixed_d_s *CORBA_fixed_alloc( ++ CORBA_unsigned_short d); ++ ++extern void CORBA_free( ++ void *storage); ++ ++extern int ORBit_parse_inet( ++ CORBA_Object obj, ++ char *hostname, ++ unsigned short port, ++ gboolean existing_only); ++ ++extern int ORBit_parse_unixsock(CORBA_Object obj, ++ char *sockpath, ++ gboolean existing_only); ++ ++/**** ++ This function lets you use your own event loop, if you so wish. ++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers, ++ which are app-settable (you should set them before CORBA_ORB_init, ++ if you want them to be useful) ++ ****/ ++ ++ /* needs to be called by your event loop when data comes in on one of the ++ GIOPConnection fd's */ ++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev); ++ void ORBit_handle_incoming(GIOPConnection *connection); ++ ++/* Returns CORBA_TRUE if the request is OK to proceed. */ ++typedef enum { ++ ORBIT_MESSAGE_BAD, ++ ORBIT_MESSAGE_ALLOW, ++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on ++ this connection with no checking */ ++} ORBit_MessageValidationResult; ++typedef ORBit_MessageValidationResult (*ORBit_request_validate) ++ (CORBA_unsigned_long request_id, ++ CORBA_Principal *principal, ++ CORBA_char *operation); ++void ORBit_set_request_validation_handler(ORBit_request_validate validator); ++ ++extern struct iovec ORBit_default_principal_iovec; ++void ORBit_set_default_principal(CORBA_Principal *principal); ++ ++extern CORBA_unsigned_long ORBit_class_assignment_counter; ++ ++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info); ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* !_ORBIT_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit.h.in linux-2.4.1-korbit/net/korbit/orb/orbit.h.in +--- linux-2.4.1/net/korbit/orb/orbit.h.in Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit.h.in Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,205 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@acm.org> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++/* these two blocks are outside of the main header for good reason... ++ People may include headers from many different stubs, and we want to ++ have the version checked on all of them. ++ */ ++#ifndef ORBIT_SERIAL ++#define ORBIT_SERIAL @ORBIT_SERIAL@ ++#endif ++ ++#ifdef ORBIT_IDL_SERIAL ++#if ORBIT_IDL_SERIAL < @ORBIT_SERIAL@ ++#error "You need to rerun 'orbit-idl' on the .idl file whose stubs you are using. These stubs were generated with an older version of ORBit, and need to be regenerated." ++#endif ++#endif ++ ++#ifndef _ORBIT_H_ ++#define _ORBIT_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#include <glib.h> ++ ++#define BACKWARDS_COMPAT_0_4 ++#undef NOT_BACKWARDS_COMPAT_0_4 ++ ++#include <sys/types.h> ++#include <sys/uio.h> ++#include <IIOP/IIOP.h> ++#include <ORBitutil/util.h> ++#include <orb/orbit_config.h> ++#include <orb/orbit_types.h> ++#include <orb/allocators.h> ++#include <orb/cdr.h> ++#include <orb/dii.h> ++#include <orb/dynany.h> ++#include <orb/env.h> ++#include <orb/iop.h> ++#include <orb/ir.h> ++#include <orb/options.h> ++#include <orb/orb.h> ++#include <orb/poa.h> ++#include <orb/sequences.h> ++#include <orb/orbit_typecode.h> ++#include <orb/typecode.h> ++ ++#ifndef ORBIT_MAJOR_VERSION ++#define ORBIT_MAJOR_VERSION (@ORBIT_MAJOR_VERSION@) ++#define ORBIT_MINOR_VERSION (@ORBIT_MINOR_VERSION@) ++#define ORBIT_MICRO_VERSION (@ORBIT_MICRO_VERSION@) ++#endif ++ ++extern const guint orbit_major_version, ++ orbit_minor_version, ++ orbit_micro_version; ++extern const char orbit_version[]; ++ ++extern void CORBA_any_set_release( ++ CORBA_any *, ++ CORBA_boolean); ++ ++extern CORBA_boolean CORBA_any_get_release( ++ CORBA_any *); ++ ++extern void CORBA_sequence_set_release( ++ void *, ++ CORBA_boolean); ++ ++extern CORBA_boolean CORBA_sequence_get_release( ++ void *); ++ ++#define CORBA_any__alloc CORBA_any_alloc ++extern CORBA_any *CORBA_any_alloc( ++ void); ++ ++extern gpointer CORBA_any__free(gpointer mem, gpointer func_data, ++ CORBA_boolean free_strings); ++extern gpointer CORBA_TypeCode__free(gpointer mem, gpointer func_data, ++ CORBA_boolean free_strings); ++ ++extern CORBA_boolean ORBit_any_equivalent( ++ CORBA_any obj, ++ CORBA_any any, ++ CORBA_Environment *ev); ++ ++extern CORBA_char *CORBA_string_dup(const CORBA_char *string); ++extern CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len); ++extern gpointer CORBA_string__free(gpointer str, gpointer dat, CORBA_boolean free_strings); ++ ++gpointer CORBA_Object__free(gpointer str, gpointer dat, CORBA_boolean free_strings); ++ ++extern CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len); ++#define CORBA_wstring_free CORBA_string_free ++ ++/* 19.14 */ ++extern CORBA_long CORBA_fixed_integer_part( ++ const void *fp); ++ ++extern CORBA_long CORBA_fixed_fraction_part( ++ const void *fp); ++ ++extern void CORBA_fixed_set( ++ void *rp, ++ CORBA_long i, ++ CORBA_long f); ++ ++extern void CORBA_fixed_add( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_sub( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_mul( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern void CORBA_fixed_div( ++ void *rp, ++ const void *f1p, ++ const void *f2p); ++ ++extern CORBA_fixed_d_s *CORBA_fixed_alloc( ++ CORBA_unsigned_short d); ++ ++extern void CORBA_free( ++ void *storage); ++ ++extern int ORBit_parse_inet( ++ CORBA_Object obj, ++ char *hostname, ++ unsigned short port, ++ gboolean existing_only); ++ ++extern int ORBit_parse_unixsock(CORBA_Object obj, ++ char *sockpath, ++ gboolean existing_only); ++ ++/**** ++ This function lets you use your own event loop, if you so wish. ++ Also see IIOP.h's IIOP{Add,Remove}ConnectionHandler function pointers, ++ which are app-settable (you should set them before CORBA_ORB_init, ++ if you want them to be useful) ++ ****/ ++ ++ /* needs to be called by your event loop when data comes in on one of the ++ GIOPConnection fd's */ ++void ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev); ++ void ORBit_handle_incoming(GIOPConnection *connection); ++ ++/* Returns CORBA_TRUE if the request is OK to proceed. */ ++typedef enum { ++ ORBIT_MESSAGE_BAD, ++ ORBIT_MESSAGE_ALLOW, ++ ORBIT_MESSAGE_ALLOW_ALL /* Allow all subsequent messages on ++ this connection with no checking */ ++} ORBit_MessageValidationResult; ++typedef ORBit_MessageValidationResult (*ORBit_request_validate) ++ (CORBA_unsigned_long request_id, ++ CORBA_Principal *principal, ++ CORBA_char *operation); ++void ORBit_set_request_validation_handler(ORBit_request_validate validator); ++ ++extern struct iovec ORBit_default_principal_iovec; ++void ORBit_set_default_principal(CORBA_Principal *principal); ++ ++extern CORBA_unsigned_long ORBit_class_assignment_counter; ++ ++CORBA_unsigned_long ORBit_register_class(const PortableServer_ClassInfo *class_info); ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* !_ORBIT_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_config.h linux-2.4.1-korbit/net/korbit/orb/orbit_config.h +--- linux-2.4.1/net/korbit/orb/orbit_config.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_config.h Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,9 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++#ifndef ORB_CONFIG_H ++#define ORB_CONFIG_H 1 ++ ++/* When creating a memory pool for a particular type, how many chunks ++ do we want to pre-allocated? */ ++#define ORBIT_CHUNKS_PREALLOC 2 ++ ++#endif /* ORB_CONFIG_H */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_object.c linux-2.4.1-korbit/net/korbit/orb/orbit_object.c +--- linux-2.4.1/net/korbit/orb/orbit_object.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.c Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,699 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Phil Dawes <philipd@parallax.co.uk> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++/* ++ * ORBit specific CORBA_Object functions. ++ * ++ */ ++ ++#include <string.h> ++#include "config.h" ++#include "../IIOP/iiop-endianP.h" ++#include "orbit_object_type.h" ++#include "corba_object_type.h" ++#include "allocators.h" ++#include "iop.h" ++#include <IIOP/IIOP.h> ++ ++static void ORBit_object_try_existing_connections(CORBA_Object obj); ++static void CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev); ++ ++static ORBit_RootObject_Interface CORBA_Object_epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))CORBA_Object_release_fn, ++}; ++ ++void ORBit_pseudo_object_init(ORBit_PseudoObject obj, ++ ORBit_PseudoObject_type obj_type, ++ CORBA_Environment *ev) ++{ ++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = TRUE; ++ ORBIT_ROOT_OBJECT(obj)->refs = 0; ++ ORBIT_PSEUDO_OBJECT(obj)->pseudo_object_type = obj_type; ++} ++ ++static const ORBit_RootObject_Interface CORBA_Policy__epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))CORBA_Policy_destroy ++}; ++ ++void ORBit_policy_object_init(CORBA_Policy obj, ++ CORBA_PolicyType obj_type, ++ CORBA_Environment *ev) ++{ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(obj), ++ ORBIT_PSEUDO_POLICY, ev); ++ ++ obj->policy_type = obj_type; ++ ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj), ++ (gpointer)&CORBA_Policy__epv, ++ ev); ++} ++ ++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ /* set the interface up */ ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),&CORBA_Object_epv,ev); ++ /* initialise the reference count */ ++ ORBIT_ROOT_OBJECT(obj)->refs = 0; ++ ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = FALSE; ++} ++ ++CORBA_Object ++ORBit_CORBA_Object_new(CORBA_Environment *ev) ++{ ++ CORBA_Object obj; ++ /* Create the object */ ++ obj = ORBIT_CHUNK_ALLOC(CORBA_Object); ++ memset(obj, '\0', sizeof(struct CORBA_Object_struct)); ++ ++ ORBit_object_reference_init(obj, ev); ++ ++ return obj; ++ ++} ++ ++void ++ORBit_set_object_key(ORBit_Object_info *info) ++{ ++ g_assert(info); ++ ++ g_assert(info->object_key._length); ++ ++ info->object_key_data = g_malloc(sizeof(CORBA_unsigned_long) + info->object_key._length); ++ info->object_key_data->_length = info->object_key._length; ++ memcpy(info->object_key_data->_buffer, info->object_key._buffer, info->object_key._length); ++ ++ info->object_key_vec.iov_base = ++ (gpointer)info->object_key_data; ++ info->object_key_vec.iov_len = sizeof(CORBA_unsigned_long) + info->object_key._length; ++} ++ ++static void ORBit_free_profile(gpointer item, gpointer data) ++{ ++ ORBit_Object_info *info=(ORBit_Object_info *)item; ++ ++ g_assert(info); ++ ++ g_free(info->object_key_data); ++ CORBA_free(info->object_key._buffer); ++ ++ if(info->profile_type == IOP_TAG_INTERNET_IOP) { ++ g_free(info->tag.iopinfo.host); ++ } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { ++ g_free(info->tag.orbitinfo.unix_sock_path); ++ } else { ++ g_warning("ORBit_free_profile asked to free type %d", info->profile_type); ++ } ++ ++ g_free(info); /* Check its safe to free the item within a foreach func */ ++} ++ ++void ORBit_delete_profiles(GSList *profile_list) ++{ ++ g_slist_foreach(profile_list, ORBit_free_profile, NULL); ++ g_slist_free(profile_list); ++} ++ ++/* this function is wired up to the RootObject interface */ ++void ++CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ ++ g_assert(obj!=NULL); ++ ++ ORBIT_ROOT_OBJECT_UNREF(obj); ++ ++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) { ++ g_hash_table_remove(obj->orb->objrefs, obj); ++ ++ if(obj->connection) ++ giop_connection_unref(obj->connection); ++ ++ g_free(obj->object_id); ++ ORBit_delete_profiles(obj->profile_list); ++ ORBit_delete_profiles(obj->forward_locations); ++ ++ ORBIT_CHUNK_FREE(CORBA_Object, obj); ++ } ++} ++ ++ ++/* Sets the interface member in the RootObject to the epv specified*/ ++void ++ORBit_RootObject_set_interface(ORBit_RootObject obj, ++ ORBit_RootObject_Interface* epv, ++ CORBA_Environment *ev) ++{ ++ g_assert(obj!=NULL); ++ g_assert(epv!=NULL); ++ ++ obj->interface = epv; ++} ++ ++#define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); \ ++GIOP_RECV_BUFFER(recv_buffer)->cur = ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) + sizeof(x); \ ++}G_STMT_END ++#define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x)) ++ ++CORBA_Object ++ORBit_create_object_with_info(GSList *profiles, ++ const CORBA_char *type_id, ++ CORBA_ORB orb, ++ CORBA_Environment *ev) ++{ ++ CORBA_Object new; ++ struct CORBA_Object_struct refcheck; ++ ++ if(!type_id || !*type_id) { ++ g_warning("Failing object creation because object has no type"); ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_MAYBE); ++ return CORBA_OBJECT_NIL; ++ } ++ ++ if(g_slist_length(profiles) < 1) { ++ g_warning("Failing object creation because object has no profiles"); ++ CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_MAYBE); ++ return CORBA_OBJECT_NIL; ++ } ++ ++ /* XXX badhack :) */ ++ refcheck.object_id = type_id; ++ refcheck.profile_list = profiles; ++ ++ new = g_hash_table_lookup(orb->objrefs, &refcheck); ++ if(new) { ++ ORBit_delete_profiles(profiles); ++ return CORBA_Object_duplicate(new, ev); ++ } ++ ++ new = ORBit_CORBA_Object_new(ev); ++ new->connection = NULL; ++ new->object_id = g_strdup(type_id); ++ new->orb = (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)orb, ev); ++ new->profile_list = profiles; ++ new->active_profile = NULL; ++ ++ ORBit_object_try_existing_connections(new); ++ ++ g_hash_table_insert(orb->objrefs, new, new); ++ ++ return CORBA_Object_duplicate(new, ev); ++} ++ ++static ORBit_Object_info * ++ORBit_demarshal_profile(GIOPRecvBuffer *recv_buffer, IOP_ProfileId profile_id) ++{ ++ ORBit_Object_info *object_info; ++ CORBA_unsigned_long subpart_len; ++ CORBA_octet o; ++ CDR_Codec codec_d; ++ CDR_Codec *codec=&codec_d; ++ ++ object_info = g_new0(ORBit_Object_info, 1); ++ ++ switch(profile_id) { ++ case IOP_TAG_INTERNET_IOP: ++ GET_ATOM(subpart_len); /* The length of the embedded sequence */ ++ CDR_codec_init_static(codec); ++ codec->buffer = recv_buffer->cur; ++ codec->release_buffer = CORBA_FALSE; ++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len; ++ ++ codec->readonly = CORBA_TRUE; ++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS; ++ codec->buf_len = subpart_len; ++ ++ CDR_get_octet(codec, &o); ++ codec->data_endian = o; ++ ++ object_info->profile_type = IOP_TAG_INTERNET_IOP; ++ CDR_get_octet(codec, &object_info->iiop_major); ++ ++ if(object_info->iiop_major != 1) ++ goto error_exit; ++ /* XXX should we check for a specific minor version? */ ++ CDR_get_octet(codec, &object_info->iiop_minor); ++ ++ CDR_get_string(codec, &object_info->tag.iopinfo.host); ++ ++ CDR_get_ushort(codec, &object_info->tag.iopinfo.port); ++ ++ CDR_get_seq_begin(codec, &object_info->object_key._length); ++ object_info->object_key._buffer = ++ ORBit_alloc(object_info->object_key._length, NULL, NULL); ++ CDR_buffer_gets(codec, object_info->object_key._buffer, ++ object_info->object_key._length); ++ object_info->object_key._maximum = object_info->object_key._release = 0; ++ ++ ORBit_set_object_key(object_info); ++ ++ return(object_info); ++ break; ++ ++ case IOP_TAG_MULTIPLE_COMPONENTS: ++ default: ++ GET_ATOM(subpart_len); ++ g_warning("IOP_TAG_MULTIPLE_COMPONENTS decoding needs finishing"); ++ object_info->profile_type = IOP_TAG_MULTIPLE_COMPONENTS; ++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len; ++ return(object_info); ++ break; ++ ++ case IOP_TAG_ORBIT_SPECIFIC: ++ GET_ATOM(subpart_len); ++ CDR_codec_init_static(codec); ++ codec->buffer = recv_buffer->cur; ++ codec->release_buffer = CORBA_FALSE; ++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + subpart_len; ++ ++ codec->readonly = CORBA_TRUE; ++ codec->host_endian = codec->data_endian = FLAG_ENDIANNESS; ++ codec->buf_len = subpart_len; ++ ++ CDR_get_octet(codec, &o); ++ codec->data_endian = o; ++ ++ object_info->profile_type = IOP_TAG_ORBIT_SPECIFIC; ++ CDR_get_octet(codec, &object_info->iiop_major); ++ ++ if(object_info->iiop_major != 1) ++ goto error_exit; ++ /* XXX should we check for a specific minor version? */ ++ CDR_get_octet(codec, &object_info->iiop_minor); ++ ++ CDR_get_string(codec, &object_info->tag.orbitinfo.unix_sock_path); ++ CDR_get_ushort(codec, &object_info->tag.orbitinfo.ipv6_port); ++ ++ CDR_get_seq_begin(codec, &object_info->object_key._length); ++ object_info->object_key._buffer = ++ ORBit_alloc(object_info->object_key._length, NULL, NULL); ++ CDR_buffer_gets(codec, object_info->object_key._buffer, ++ object_info->object_key._length); ++ object_info->object_key._maximum = object_info->object_key._release = 0; ++ ++ ORBit_set_object_key(object_info); ++ ++ return(object_info); ++ break; ++ } ++ ++error_exit: ++ g_message("demarshal_profile(): IIOP major is %d", ++ object_info->iiop_major); ++ g_free(object_info); ++ ++ return(NULL); ++} ++ ++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer) ++{ ++ GSList *profiles=NULL; ++ ORBit_Object_info *object_info; ++ CORBA_unsigned_long len, seq_len; ++ IOP_ProfileId profile_id; ++ int i; ++ ++ /* Get type_id */ ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(len); ++ ++ if(len == 0) ++ return(NULL); ++ ++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len; ++ ++ /* Decode the sequence<TaggedProfile> */ ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(seq_len); ++ for(i = 0; i < seq_len; i++) { ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(profile_id); ++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id); ++ if(object_info==NULL) { ++ goto error_exit; ++ } else { ++ profiles=g_slist_append(profiles, object_info); ++ } ++ } ++ ++ return(profiles); ++ ++error_exit: ++ ORBit_delete_profiles(profiles); ++ return(NULL); ++} ++ ++CORBA_Object ++ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer, CORBA_ORB orb) ++{ ++ GSList *profiles=NULL; ++ ORBit_Object_info *object_info; ++ CORBA_char *type_id; ++ CORBA_unsigned_long len, seq_len; ++ IOP_ProfileId profile_id; ++ int i; ++ CORBA_Environment ev; ++ CORBA_Object retval; ++ ++ CORBA_exception_init(&ev); ++ ++ /* Get type_id */ ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(len); ++ ++ type_id = recv_buffer->cur; ++ recv_buffer->cur = ((guchar *)recv_buffer->cur) + len; ++ ++ /* Decode the sequence<TaggedProfile> */ ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(seq_len); ++ ++ if(!seq_len) ++ return CORBA_OBJECT_NIL; ++ ++ for(i = 0; i < seq_len; i++) { ++ ALIGNFOR(CORBA_unsigned_long); ++ GET_ATOM(profile_id); ++ object_info=ORBit_demarshal_profile(recv_buffer, profile_id); ++ if(object_info) ++ profiles=g_slist_append(profiles, object_info); ++ } ++ ++ if(!profiles) ++ goto error_exit; ++ ++ retval = ORBit_create_object_with_info(profiles, type_id, orb, &ev); ++ ++ return retval; ++ ++ error_exit: ++ ORBit_delete_profiles(profiles); ++ ++ CORBA_exception_set_system(&ev, ex_CORBA_MARSHAL, ++ CORBA_COMPLETED_MAYBE); ++ return CORBA_OBJECT_NIL; ++} ++ ++static void ORBit_marshal_profile(gpointer item, gpointer data) ++{ ++ ORBit_Object_info *info = (ORBit_Object_info *)item; ++ GIOPSendBuffer *send_buffer = (GIOPSendBuffer *)data; ++ static const CORBA_unsigned_long ioptag = IOP_TAG_INTERNET_IOP, ++ orbittag = IOP_TAG_ORBIT_SPECIFIC; ++ CDR_Codec codec_d; ++ CDR_Codec *codec = &codec_d; ++ CORBA_unsigned_long len; ++ CORBA_octet codecbuf[2048]; ++ static const CORBA_octet oc_endian = FLAG_ENDIANNESS; ++ static const CORBA_octet iiopversion[] = {1,0}; ++ ++ g_assert(info); ++ g_assert(send_buffer); ++ ++ if(info->profile_type == IOP_TAG_INTERNET_IOP) { ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), ++ &ioptag, sizeof(ioptag)); ++ ++ CDR_codec_init_static(codec); ++ codec->buffer = codecbuf; ++ codec->buf_len = 2048; ++ codec->release_buffer = CORBA_FALSE; ++ codec->readonly = CORBA_FALSE; ++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS; ++ CDR_put_octet(codec, oc_endian); ++ CDR_put_octet(codec, iiopversion[0]); ++ CDR_put_octet(codec, iiopversion[1]); ++ CDR_put_string(codec, info->tag.iopinfo.host); ++ CDR_put_ushort(codec, info->tag.iopinfo.port); ++ CDR_put_ulong(codec, info->object_key._length); ++ CDR_put_octets(codec, info->object_key._buffer, ++ info->object_key._length); ++ len = codec->wptr; ++ giop_send_buffer_append_mem_indirect_a(send_buffer, ++ &len, sizeof(len)); ++ giop_send_buffer_append_mem_indirect(send_buffer, ++ codec->buffer, codec->wptr); ++ } else if(info->profile_type==IOP_TAG_ORBIT_SPECIFIC) { ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), ++ &orbittag, sizeof(orbittag)); ++ CDR_codec_init_static(codec); ++ codec->buffer = codecbuf; ++ codec->release_buffer = CORBA_FALSE; ++ codec->buf_len = 2048; ++ codec->readonly = CORBA_FALSE; ++ codec->data_endian = codec->host_endian = FLAG_ENDIANNESS; ++ CDR_put_octet(codec, oc_endian); ++ CDR_put_octets(codec, (gpointer)iiopversion, sizeof(iiopversion)); ++ CDR_put_string(codec, info->tag.orbitinfo.unix_sock_path); ++ CDR_put_ushort(codec, info->tag.orbitinfo.ipv6_port); ++ CDR_put_ulong(codec, info->object_key._length); ++ CDR_put_octets(codec, info->object_key._buffer, ++ info->object_key._length); ++ len = codec->wptr; ++ giop_send_buffer_append_mem_indirect_a(send_buffer, ++ &len, sizeof(len)); ++ giop_send_buffer_append_mem_indirect(send_buffer, ++ codec->buffer, codec->wptr); ++ } else { ++ g_warning("ORBit_marshal_profile ask to marshal type %d\n", info->profile_type); ++ } ++} ++ ++void ++ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj) ++{ ++ CORBA_unsigned_long len; ++ ++ ++ if(!obj) { ++ static const CORBA_unsigned_long zero = 0, one = 1; ++ /* zero-length typename */ ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), ++ &one, sizeof(one)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), ++ &zero, 1); ++ ++ /* zero profiles */ ++ giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), ++ &zero, sizeof(zero)); ++ return; ++ } ++ g_return_if_fail(ORBIT_ROOT_OBJECT(obj)->refs > 0); ++ ++ len = strlen(obj->object_id) + 1; ++ giop_send_buffer_append_mem_indirect_a(send_buffer, &len, ++ sizeof(len)); ++ giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), ++ obj->object_id, len); ++ ++ len = g_slist_length(obj->profile_list); ++ giop_send_buffer_append_mem_indirect_a(GIOP_SEND_BUFFER(send_buffer), ++ &len, sizeof(len)); ++ ++ /* Marshal active first? */ ++ g_slist_foreach(obj->profile_list, ORBit_marshal_profile, send_buffer); ++} ++ ++static void ORBit_test_profile(gpointer item, gpointer data) ++{ ++ ORBit_Object_info *info = (ORBit_Object_info *)item; ++ CORBA_Object obj = (CORBA_Object)data; ++ ++ if(obj->active_profile != NULL) ++ return; /* we already have a good profile */ ++ ++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { ++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, TRUE)) { ++ /* success */ ++ obj->active_profile=info; ++ } ++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) { ++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, TRUE)) { ++ /* success */ ++ obj->active_profile=info; ++ } ++ } ++} ++ ++static void ++ORBit_object_try_existing_connections(CORBA_Object obj) ++{ ++ g_slist_foreach(obj->profile_list, ORBit_test_profile, obj); ++} ++ ++static void ORBit_activate_profile(gpointer item, gpointer data) ++{ ++ ORBit_Object_info *info = (ORBit_Object_info *)item; ++ CORBA_Object obj = (CORBA_Object)data; ++ ++ if(obj->active_profile != NULL) ++ return; /* we already have a good profile */ ++ ++ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { ++ if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, FALSE)) { ++ /* success */ ++ obj->active_profile=info; ++ } ++ } else if(info->profile_type == IOP_TAG_INTERNET_IOP) { ++ if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, FALSE)) { ++ /* success */ ++ obj->active_profile=info; ++ } ++ } ++} ++ ++GIOPConnection * ++_ORBit_object_get_connection(CORBA_Object obj) ++{ ++ g_return_val_if_fail(obj, NULL); ++ ++ if (obj->connection) { ++ giop_connection_unref(obj->connection); ++ obj->connection = NULL; ++ obj->active_profile = NULL; ++ } ++ ++ g_slist_foreach(obj->profile_list, ORBit_activate_profile, obj); ++ ++ if(obj->active_profile == NULL || !obj->connection) ++ return NULL; ++ ++ obj->connection->orb_data = obj->orb; ++ ++ return obj->connection; ++} ++ ++GIOPConnection * ++ORBit_object_get_forwarded_connection(CORBA_Object obj) ++{ ++ g_return_val_if_fail(obj, NULL); ++ ++ if (obj->connection) { ++ giop_connection_unref(obj->connection); ++ obj->connection = NULL; ++ obj->active_profile = NULL; ++ } ++ ++ g_slist_foreach(obj->forward_locations, ORBit_activate_profile, obj); ++ ++ if(obj->active_profile == NULL || !obj->connection) ++ return NULL; ++ ++ obj->connection->orb_data = obj->orb; ++ ++ return obj->connection; ++} ++ ++/* This function is heavily based on the idl stubs output. Any changes there ++ will probably have to be reflected here also. */ ++ ++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev) ++{ ++ GIOPConnection *cnx; ++ GIOPSendBuffer *send_buffer; ++ GIOPRecvBuffer *recv_buffer; ++ GIOP_unsigned_long request_id; ++ ++ g_return_if_fail(obj!=NULL); ++ g_return_if_fail(ev!=NULL); ++ ++ /* Send a LOCATE_REQUEST, wait for a LOCATE_REPLY. The reply will ++ either say "Object here", or will carry a new location. We set ++ obj->active_profile appropriately */ ++ ++ cnx=ORBit_object_get_connection(obj); ++ if((cnx==NULL) || (obj->active_profile==NULL)) { ++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO); ++ return; ++ } ++ request_id=giop_get_request_id(); ++ send_buffer=giop_send_locate_request_buffer_use(cnx, request_id, &(obj->active_profile->object_key_vec)); ++ if(!send_buffer) { ++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ giop_send_buffer_write(send_buffer); ++ giop_send_buffer_unuse(send_buffer); ++ ++ recv_buffer=giop_recv_locate_reply_buffer_use(request_id, TRUE); ++ if(recv_buffer==NULL || recv_buffer->message_buffer.message_header.message_type!=GIOP_LOCATEREPLY) { ++ CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_MAYBE); ++ if(recv_buffer) ++ giop_recv_buffer_unuse(recv_buffer); ++ ++ return; ++ } ++ ++ ev->_major=CORBA_NO_EXCEPTION; ++ switch(recv_buffer->message.u.locate_reply.locate_status) { ++ case GIOP_UNKNOWN_OBJECT: ++ CORBA_exception_set_system(ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO); ++ break; ++ ++ case GIOP_OBJECT_HERE: ++ /* No further processing necessary */ ++ break; ++ ++ case GIOP_OBJECT_FORWARD: ++ /* We've been forwarded onto somewhere else. The message body ++ contains the new IOR */ ++ if(obj->forward_locations != NULL) { ++ ORBit_delete_profiles(obj->forward_locations); ++ } ++ obj->forward_locations=ORBit_demarshal_IOR(recv_buffer); ++ ++ /* This will adjust obj->active_profile */ ++ cnx=ORBit_object_get_forwarded_connection(obj); ++ break; ++ ++ default: ++ g_message("Bad Reply in ORBit_locate_object()\n"); ++ break; ++ ++ } ++ ++ giop_recv_buffer_unuse(recv_buffer); ++} ++ ++GIOPConnection * ++ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj) ++{ ++ GIOPConnection *retval; ++ ++ if(obj->forward_locations) ++ ORBit_delete_profiles(obj->forward_locations); ++ obj->forward_locations = ORBit_demarshal_IOR(rb); ++ ++ retval = ORBit_object_get_forwarded_connection(obj); ++ giop_recv_buffer_unuse(rb); ++ ++ return retval; ++} +diff -urN linux-2.4.1/net/korbit/orb/orbit_object.h linux-2.4.1-korbit/net/korbit/orb/orbit_object.h +--- linux-2.4.1/net/korbit/orb/orbit_object.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,114 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Phil Dawes <philipd@parallax.co.uk> ++ * ++ */ ++ ++/* ++ * ORBit specific CORBA_Object funcitons. ++ * ++ */ ++#ifndef _ORBIT_ORBIT_OBJECT_H_ ++#define _ORBIT_ORBIT_OBJECT_H_ ++ ++#include <IIOP/IIOP.h> ++#include "corba_object.h" ++ ++extern CORBA_Object ORBit_CORBA_Object_new(CORBA_Environment *ev); ++extern void ORBit_CORBA_Object_free(CORBA_Object obj, CORBA_Environment *ev); ++ ++ ++typedef enum { ++ ORBIT_PSEUDO_ORB, ++ ORBIT_PSEUDO_POA, ++ ORBIT_PSEUDO_POAMANAGER, ++ ORBIT_PSEUDO_POLICY, ++ ORBIT_PSEUDO_TYPECODE, ++ ORBIT_PSEUDO_REQUEST, ++ ORBIT_PSEUDO_SERVERREQUEST, ++ ORBIT_PSEUDO_CONTEXT ++} ORBit_PseudoObject_type; ++typedef struct ORBit_PseudoObject_struct *ORBit_PseudoObject; ++ ++void ORBit_pseudo_object_init(ORBit_PseudoObject obj, ++ ORBit_PseudoObject_type obj_type, ++ CORBA_Environment *ev); ++void ORBit_policy_object_init(CORBA_Policy obj, ++ CORBA_PolicyType obj_type, ++ CORBA_Environment *ev); ++ ++/* Use ORBit_CORBA_Object_new() */ ++void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev); ++ ++typedef struct { ++ CORBA_char *host; ++ CORBA_unsigned_short port; ++} TAG_INTERNET_IOP_info; ++ ++typedef struct { ++ CORBA_char *unix_sock_path; ++ CORBA_unsigned_short ipv6_port; ++} TAG_ORBIT_SPECIFIC_info; ++ ++typedef struct { ++ int fill_me_in; ++} TAG_MULTIPLE_COMPONENTS_info; ++ ++typedef struct { ++ CORBA_octet iiop_major, iiop_minor; ++ IOP_ProfileId profile_type; ++ union { ++ TAG_INTERNET_IOP_info iopinfo; ++ TAG_ORBIT_SPECIFIC_info orbitinfo; ++ TAG_MULTIPLE_COMPONENTS_info mcinfo; ++ } tag; ++ ++ /* If the object key is invariant wrt to the various profiles, then ++ this should probably go in CORBA_Object_struct ++ */ ++ CORBA_sequence_octet object_key; ++ struct { CORBA_unsigned_long _length; char _buffer[1]; } *object_key_data; ++ struct iovec object_key_vec; ++} ORBit_Object_info; ++ ++void ORBit_set_object_key(ORBit_Object_info *info); ++ ++CORBA_Object ORBit_create_object_with_info(GSList *profiles, ++ const CORBA_char *type_id, ++ CORBA_ORB orb, ++ CORBA_Environment *ev); ++ ++#define ORBit_object_get_connection(obj) \ ++ ((obj)->connection && (obj)->connection->is_valid)?((obj)->connection):_ORBit_object_get_connection(obj) ++GIOPConnection *_ORBit_object_get_connection(CORBA_Object obj); ++GIOPConnection *ORBit_object_get_forwarded_connection(CORBA_Object obj); ++void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev); ++ ++void ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj); ++CORBA_Object ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer, ++ CORBA_ORB orb); ++GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer); ++ ++extern void ORBit_delete_profiles(GSList *profile_list); ++GIOPConnection *ORBit_handle_location_forward(GIOPRecvBuffer *rb, CORBA_Object obj); ++ ++#endif /* _ORBIT_ORBIT_OBJECT_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_object_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h +--- linux-2.4.1/net/korbit/orb/orbit_object_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_object_type.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,87 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * Philip Dawes ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++#ifndef _ORBIT_ORBIT_OBJECT_TYPE_H_ ++#define _ORBIT_ORBIT_OBJECT_TYPE_H_ ++ ++#include "orbit_object.h" ++ ++ ++/****** Root object **********/ ++/*****************************/ ++ ++typedef struct ORBit_RootObject_Interface_struct ORBit_RootObject_Interface; ++struct ORBit_RootObject_Interface_struct ++{ ++ void (*release)(gpointer obj, CORBA_Environment *ev); ++}; ++ ++ ++ ++#define ORBIT_ROOT_OBJECT(x) ((ORBit_RootObject)(x)) ++ ++ ++typedef struct ORBit_RootObject_struct *ORBit_RootObject; ++struct ORBit_RootObject_struct { ++ ORBit_RootObject_Interface* interface; /* the interface */ ++ ++ guchar is_pseudo_object; ++ gint refs; ++}; ++ ++ ++/* Reference counting interface */ ++ ++#define ORBIT_ROOT_OBJECT_REF(obj) (ORBIT_ROOT_OBJECT(obj)->refs++) ++#define ORBIT_ROOT_OBJECT_UNREF(obj) (ORBIT_ROOT_OBJECT(obj)->refs--) ++ ++ ++ /* Virtual function interface*/ ++ ++#define ORBIT_ROOT_OBJECT_release(obj,ev) \ ++(ORBIT_ROOT_OBJECT(obj)->interface->release(obj,ev)) ++ ++ ++ ++extern void ORBit_RootObject_set_interface(ORBit_RootObject obj, ++ ORBit_RootObject_Interface* epv, ++ CORBA_Environment *ev); ++ ++ ++ ++/****** Pseudo object --> RootObject ********/ ++/*********************************************/ ++ ++#define ORBIT_PSEUDO_OBJECT(x) ((ORBit_PseudoObject)(x)) ++ ++struct ORBit_PseudoObject_struct { ++ struct ORBit_RootObject_struct parent; ++ ORBit_PseudoObject_type pseudo_object_type; ++}; ++ ++ ++#endif /* !_ORBIT_CORBA_OBJECT_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.c linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c +--- linux-2.4.1/net/korbit/orb/orbit_poa.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.c Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,809 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Phil Dawes <philipd@parallax.co.uk> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++/* ++ * ORBit specific POA funcitons. ++ * ++ */ ++ ++#include <string.h> ++#include "orbit.h" ++#include "orbit_poa_type.h" ++#include "orbit_poa.h" ++#include "genrand.h" ++ ++#define POA_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN) ++#define OBJ_KEY_LEN (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN) ++ ++static void ORBit_POAManager_release(PortableServer_POAManager poa_mgr, ++ CORBA_Environment *ev); ++ ++static void ORBit_POA_release(PortableServer_POA poa, ++ CORBA_Environment *ev); ++ ++static PortableServer_Servant ++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer, ++ PortableServer_ServantLocator_Cookie *the_cookie, ++ PortableServer_ObjectId *oid, ++ ORBit_POAObject *fake_obj_impl, ++ CORBA_Environment *ev); ++static void ++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant, ++ PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer, ++ PortableServer_ServantLocator_Cookie cookie, ++ PortableServer_ObjectId *oid, ++ ORBit_POAObject *fake_obj_impl, ++ CORBA_Environment *ev); ++ ++static const ORBit_RootObject_Interface CORBA_POAManager_epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))ORBit_POAManager_release, ++}; ++ ++static const ORBit_RootObject_Interface CORBA_POA_epv = ++{ ++ (void (*)(gpointer, CORBA_Environment *))ORBit_POA_release, ++}; ++ ++guint ++g_sequence_octet_hash(CORBA_sequence_octet *so) ++{ ++ const char *s = (char*)so->_buffer; ++ const char *p, *e = ((char *)so->_buffer) + so->_length; ++ guint h=0, g; ++ ++ for(p = s; p < e; p ++) { ++ h = ( h << 4 ) + *p; ++ if ( ( g = h & 0xf0000000 ) ) { ++ h = h ^ (g >> 24); ++ h = h ^ g; ++ } ++ } ++ ++ return h; ++} ++ ++gint ++g_sequence_octet_compare(CORBA_sequence_octet *s1, CORBA_sequence_octet *s2) ++{ ++ if(s2->_length != s1->_length) ++ return FALSE; ++ ++ return !memcmp(s1->_buffer, s2->_buffer, s1->_length); ++} ++ ++PortableServer_POAManager ++ORBit_POAManager_new(CORBA_Environment *ev) ++{ ++ PortableServer_POAManager poa_mgr; ++ ++ poa_mgr = g_new0(struct PortableServer_POAManager_type, 1); ++ ++ if(poa_mgr == NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ goto error; ++ } ++ ++ /* Initialise poa manager */ ++ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa_mgr), ++ ORBIT_PSEUDO_POAMANAGER, ev); ++ ORBIT_ROOT_OBJECT(poa_mgr)->refs = 0; ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa_mgr), ++ (gpointer)&CORBA_POAManager_epv, ev); ++ ++ poa_mgr->poa_collection = NULL; ++ poa_mgr->state = PortableServer_POAManager_HOLDING; ++ ++ return poa_mgr; ++ ++error: ++ if(poa_mgr != NULL){ ++ ORBit_POAManager_release(poa_mgr, ev); ++ } ++ return NULL; ++} ++ ++static void ++ORBit_POAManager_release(PortableServer_POAManager poa_mgr, ++ CORBA_Environment *ev) ++{ ++ ++ if(--(ORBIT_ROOT_OBJECT(poa_mgr)->refs) > 0) ++ return; ++ ++ if(poa_mgr != NULL) { ++ if(poa_mgr->poa_collection != NULL) { ++ g_slist_free(poa_mgr->poa_collection); ++ poa_mgr->poa_collection = NULL; ++ } ++ g_free(poa_mgr); ++ poa_mgr = NULL; ++ } ++} ++ ++static void ++ORBit_POAManager_register_poa(PortableServer_POAManager poa_mgr, ++ PortableServer_POA poa, ++ CORBA_Environment *ev) ++{ ++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa); ++ poa_mgr->poa_collection = ++ g_slist_append(poa_mgr->poa_collection, poa); ++} ++ ++static void ++ORBit_POAManager_unregister_poa(PortableServer_POAManager poa_mgr, ++ PortableServer_POA poa, ++ CORBA_Environment *ev) ++{ ++ poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa); ++} ++ ++static void ++ORBit_POA_set_policy(PortableServer_POA poa, ++ CORBA_Policy policy, ++ CORBA_Environment *ev) ++{ ++ switch(policy->policy_type) { ++ case PortableServer_THREAD_POLICY_ID: ++ poa->thread = ((PortableServer_ThreadPolicy)policy)->value; ++ break; ++ case PortableServer_LIFESPAN_POLICY_ID: ++ poa->lifespan = ((PortableServer_LifespanPolicy)policy)->value; ++ break; ++ case PortableServer_ID_UNIQUENESS_POLICY_ID: ++ poa->id_uniqueness = ((PortableServer_IdUniquenessPolicy)policy)->value; ++ break; ++ case PortableServer_ID_ASSIGNMENT_POLICY_ID: ++ poa->id_assignment = ((PortableServer_IdAssignmentPolicy)policy)->value; ++ break; ++ case PortableServer_IMPLICIT_ACTIVATION_POLICY_ID: ++ poa->implicit_activation = ((PortableServer_ImplicitActivationPolicy)policy)->value; ++ break; ++ case PortableServer_SERVANT_RETENTION_POLICY_ID: ++ poa->servant_retention = ((PortableServer_ServantRetentionPolicy)policy)->value; ++ break; ++ case PortableServer_REQUEST_PROCESSING_POLICY_ID: ++ poa->request_processing = ((PortableServer_ServantRetentionPolicy)policy)->value; ++ break; ++ default: ++ g_warning("Unknown policy type, cannot set it on this POA"); ++ } ++} ++ ++ ++static void ++ORBit_POA_check_policy_conflicts(PortableServer_POA poa, ++ CORBA_Environment *ev) ++{ ++ ++ /* Check for those policy combinations that aren't allowed */ ++ if ((poa->servant_retention == PortableServer_NON_RETAIN && ++ poa->request_processing == PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY) || ++ ++ (poa->request_processing == PortableServer_USE_DEFAULT_SERVANT && ++ poa->id_uniqueness == PortableServer_UNIQUE_ID) || ++ ++ (poa->implicit_activation == PortableServer_IMPLICIT_ACTIVATION && ++ (poa->id_assignment == PortableServer_USER_ID || ++ poa->servant_retention == PortableServer_NON_RETAIN)) ++ ) ++ { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_InvalidPolicy, ++ NULL); ++ } ++} ++ ++ ++static void ++ORBit_POA_set_policylist(PortableServer_POA poa, ++ CORBA_PolicyList *policies, ++ CORBA_Environment *ev) ++{ ++ CORBA_unsigned_long i; ++ ++ for(i = 0; i < policies->_length; i++) { ++ if(ev->_major != CORBA_NO_EXCEPTION) ++ break; ++ ORBit_POA_set_policy(poa, policies->_buffer[i], ev); ++ } ++} ++ ++PortableServer_POA ++ORBit_POA_new(CORBA_ORB orb, ++ CORBA_char *adapter_name, ++ PortableServer_POAManager the_POAManager, ++ CORBA_PolicyList *policies, ++ CORBA_Environment *ev) ++{ ++ PortableServer_POA poa; ++ ++ /* Create the object */ ++ poa = (PortableServer_POA) g_new0(struct PortableServer_POA_type, 1); ++ if(poa == NULL) { ++ CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); ++ goto error; ++ } ++ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa), ORBIT_PSEUDO_POA, ev); ++ ++ ORBIT_ROOT_OBJECT(poa)->refs = 0; ++ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa), ++ (gpointer)&CORBA_POA_epv, ev); ++ ++ if(ev->_major != CORBA_NO_EXCEPTION) goto error; ++ ++ /* If no POAManager was specified, create one */ ++ if(the_POAManager == NULL) { ++ the_POAManager = ORBit_POAManager_new(ev); ++ } ++ ++ /* Register this poa with the poa manager */ ++ if(the_POAManager != NULL) ++ ORBit_POAManager_register_poa(the_POAManager,poa,ev); ++ if(ev->_major != CORBA_NO_EXCEPTION) goto error; ++ ++ /* Wire up the poa_manager */ ++ poa->the_POAManager = the_POAManager; ++ ++ /* Initialise the child poas table */ ++ poa->child_POAs = NULL; /* initialise the slist */ ++ ++ poa->held_requests = NULL; ++ ++ poa->poaID = orb->poas->len; ++ g_ptr_array_set_size(orb->poas, orb->poas->len + 1); ++ g_ptr_array_index(orb->poas, poa->poaID) = poa; ++ ++ poa->orb = orb; ++ ++ g_return_val_if_fail(ev->_major == CORBA_NO_EXCEPTION, NULL); ++ ++ /* Need to initialise poa policies etc.. here */ ++ poa->thread = PortableServer_ORB_CTRL_MODEL; ++ poa->lifespan = PortableServer_TRANSIENT; ++ poa->id_uniqueness = PortableServer_UNIQUE_ID; ++ poa->id_assignment = PortableServer_SYSTEM_ID; ++ poa->servant_retention = PortableServer_RETAIN; ++ poa->request_processing = PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY; ++ poa->implicit_activation = PortableServer_NO_IMPLICIT_ACTIVATION; ++ if (policies) { ++ ORBit_POA_set_policylist(poa, policies, ev); ++ ORBit_POA_check_policy_conflicts(poa, ev); ++ if(ev->_major != CORBA_NO_EXCEPTION) goto error; ++ } ++ ++ /* copy the name */ ++ poa->the_name = CORBA_string_dup(adapter_name); ++ ++ poa->active_object_map = g_hash_table_new((GHashFunc)g_sequence_octet_hash, ++ (GCompareFunc)g_sequence_octet_compare); ++ poa->objnum_to_obj = g_ptr_array_new(); ++ g_ptr_array_set_size(poa->objnum_to_obj, 1); ++ g_ptr_array_index(poa->objnum_to_obj, 0) = NULL; ++ ++ orbit_genrand(poa->rand_data, ORBIT_RAND_KEY_LEN); ++ ++ return poa; ++ ++error: ++ if(poa && poa->the_name){ ++ CORBA_free(poa->the_name); ++ } ++ ++ if(poa != NULL){ ++ ORBit_POA_release(poa, NULL); ++ } ++ return NULL; ++} ++ ++static void ++ORBit_POA_release(PortableServer_POA poa, ++ CORBA_Environment *ev) ++{ ++ ORBIT_ROOT_OBJECT_UNREF(poa); ++ ++ if(ORBIT_ROOT_OBJECT(poa)->refs <= 0) { ++ CORBA_free(poa->the_name); ++ ++ g_slist_foreach(poa->child_POAs, (GFunc)CORBA_Object_release, ++ ev); ++ ++ if(poa->parent_poa) ++ ORBit_POA_remove_child(poa->parent_poa, poa, ev); ++ ++ ORBit_POAManager_unregister_poa(poa->the_POAManager, ++ poa, ev); ++ ++ g_ptr_array_index(poa->orb->poas, poa->poaID) = NULL; ++ ++ g_free(poa); ++ } ++} ++ ++void ++ORBit_POA_add_child(PortableServer_POA poa, ++ PortableServer_POA child_poa, ++ CORBA_Environment *ev) ++ ++{ ++ g_return_if_fail(poa != NULL); ++ g_return_if_fail(child_poa != NULL); ++ ++ poa->child_POAs = g_slist_prepend(poa->child_POAs, child_poa); ++} ++ ++void ++ORBit_POA_remove_child(PortableServer_POA poa, ++ PortableServer_POA child_poa, ++ CORBA_Environment *ev) ++{ ++ g_return_if_fail(poa != NULL); ++ g_return_if_fail(child_poa != NULL); ++ ++ poa->child_POAs = g_slist_remove(poa->child_POAs, child_poa); ++} ++ ++extern ORBit_request_validate ORBIT_request_validator; ++ ++gboolean ++ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer, ++ PortableServer_POA poa) ++{ ++ PortableServer_ServantBase *servant; ++ PortableServer_ServantLocator_Cookie cookie; ++ ORBit_POAObject *obj_impl = NULL, tmp_obj_impl; ++ ORBitSkeleton skel; ++ gpointer imp = NULL; ++ CORBA_Environment ev; ++ GIOPSendBuffer *send_buffer; ++ guchar *opname; ++ PortableServer_ObjectId *oid = NULL; ++ ++ CORBA_exception_init(&ev); ++ ++ switch(poa->the_POAManager->state) { ++ case PortableServer_POAManager_HOLDING: ++ poa->held_requests = g_slist_prepend(poa->held_requests, ++ recv_buffer); ++ return FALSE; ++ break; ++ case PortableServer_POAManager_DISCARDING: ++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection, ++ NULL, ++ recv_buffer->message.u.request.request_id, ++ CORBA_SYSTEM_EXCEPTION); ++ CORBA_exception_set_system(&ev, ++ ex_CORBA_TRANSIENT, ++ CORBA_COMPLETED_NO); ++ ORBit_send_system_exception(send_buffer, &ev); ++ giop_send_buffer_write(send_buffer); ++ giop_recv_buffer_unuse(recv_buffer); ++ giop_send_buffer_unuse(send_buffer); ++ CORBA_exception_free(&ev); ++ return TRUE; ++ break; ++ case PortableServer_POAManager_INACTIVE: ++ send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection, ++ NULL, ++ recv_buffer->message.u.request.request_id, ++ CORBA_SYSTEM_EXCEPTION); ++ CORBA_exception_set_system(&ev, ++ ex_CORBA_OBJ_ADAPTER, ++ CORBA_COMPLETED_NO); ++ ORBit_send_system_exception(send_buffer, &ev); ++ giop_send_buffer_write(send_buffer); ++ giop_recv_buffer_unuse(recv_buffer); ++ giop_send_buffer_unuse(send_buffer); ++ CORBA_exception_free(&ev); ++ return TRUE; ++ break; ++ case PortableServer_POAManager_ACTIVE: ++ default: ++ break; ++ } ++ ++ servant = NULL; ++ ++ if(recv_buffer->message.u.request.object_key._length ++ < (POA_KEY_LEN + sizeof(CORBA_unsigned_long))) { ++ CORBA_exception_set_system(&ev, ++ ex_CORBA_OBJECT_NOT_EXIST, ++ CORBA_COMPLETED_NO); ++ goto errout; ++ } ++ ++ obj_impl = ORBit_POA_find_oid_for_object_key(poa, &(recv_buffer->message.u.request.object_key), &oid); ++ ++ if(poa->servant_retention == PortableServer_RETAIN ++ && obj_impl) { ++ servant = obj_impl->servant; ++ oid = obj_impl->object_id; ++ } ++ ++ if(!servant) { ++ switch(poa->request_processing) { ++ case PortableServer_USE_SERVANT_MANAGER: ++ servant = ORBit_POA_ServantManager_use_servant(poa, ++ recv_buffer, ++ &cookie, ++ oid, ++ &tmp_obj_impl, ++ &ev); ++ break; ++ case PortableServer_USE_DEFAULT_SERVANT: ++ servant = poa->default_servant; ++ if(servant == NULL) { ++ CORBA_exception_set_system(&ev, ++ ex_CORBA_OBJ_ADAPTER, ++ CORBA_COMPLETED_NO); ++ goto errout; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if(!poa || !servant || !servant->_private) { ++ CORBA_exception_set_system(&ev, ++ ex_CORBA_OBJECT_NOT_EXIST, ++ CORBA_COMPLETED_NO); ++ goto errout; ++ } ++ ++ opname = recv_buffer->message.u.request.operation; ++ ++ skel = ORBIT_OBJECT_KEY(servant->_private)->class_info->relay_call(servant, recv_buffer, &imp); ++ ++ if(!skel) { ++ if (opname[0] == '_' && strcmp(opname + 1, "is_a") == 0) { ++ skel = (gpointer)&ORBit_impl_CORBA_Object_is_a; ++ } ++ else { ++ CORBA_exception_set_system(&ev, ex_CORBA_BAD_OPERATION, ++ CORBA_COMPLETED_NO); ++ goto errout; ++ } ++ } ++ else if (!imp) { ++ CORBA_exception_set_system(&ev, ex_CORBA_NO_IMPLEMENT, ++ CORBA_COMPLETED_NO); ++ goto errout; ++ } ++ ++ /* If it got through the random keys, and nobody else had the opportunity to say otherwise, it must be auth'd */ ++ ++ if(!ORBIT_request_validator) ++ GIOP_MESSAGE_BUFFER(recv_buffer)->connection->is_auth = TRUE; ++ ++ skel(servant, recv_buffer, &ev, imp); ++ ++ if(poa->request_processing == PortableServer_USE_SERVANT_MANAGER) { ++ ORBit_POA_ServantManager_unuse_servant(servant, ++ poa, ++ recv_buffer, ++ cookie, oid, ++ &tmp_obj_impl, ++ &ev); ++ } ++ ++ if(!obj_impl) ++ CORBA_free(oid); ++ ++ CORBA_exception_free(&ev); ++ ++ return TRUE; ++ ++ errout: ++ if(ev._major == CORBA_SYSTEM_EXCEPTION) { ++ GIOPSendBuffer *reply_buf; ++ ++ reply_buf = ++ giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection, ++ NULL, ++ recv_buffer->message.u.request.request_id, ++ CORBA_SYSTEM_EXCEPTION); ++ ++ ORBit_send_system_exception(reply_buf, &ev); ++ ++ giop_send_buffer_write(reply_buf); ++ giop_send_buffer_unuse(reply_buf); ++ } else /* User exceptions are handled in the skels! */ ++ g_assert(ev._major == CORBA_NO_EXCEPTION); ++ ++ if(!obj_impl) ++ CORBA_free(oid); ++ ++ CORBA_exception_free(&ev); ++ ++ return TRUE; ++} ++ ++PortableServer_POA ++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa, ++ CORBA_sequence_octet *key) ++{ ++ CORBA_unsigned_long pid; ++ ++ if(key->_length < (sizeof(CORBA_unsigned_long) + ORBIT_RAND_KEY_LEN)) ++ return NULL; ++ ++ pid = *((CORBA_unsigned_long *)key->_buffer); ++ ++ if(pid < root_poa->orb->poas->len) { ++ PortableServer_POA poa; ++ poa = g_ptr_array_index(root_poa->orb->poas, pid); ++ if(!poa) ++ return NULL; ++ if(memcmp(poa->rand_data, key->_buffer + sizeof(CORBA_unsigned_long), ORBIT_RAND_KEY_LEN)) ++ return NULL; ++ return poa; ++ } else ++ return NULL; ++} ++ ++void ++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa, ++ ORBit_POAObject *obj, ++ PortableServer_ObjectId *oid, ++ CORBA_sequence_octet *retval) ++{ ++ CORBA_long *vptr; ++ ++ g_return_if_fail(poa && (obj || oid)); ++ g_return_if_fail(retval); ++ ++ if(oid) ++ g_assert(!oid->_buffer[oid->_length - 1]); ++ ++ if(obj) ++ retval->_length = POA_KEY_LEN + OBJ_KEY_LEN; ++ else ++ retval->_length = POA_KEY_LEN + sizeof(CORBA_long) + oid->_length; ++ retval->_buffer = CORBA_octet_allocbuf(retval->_length); ++ CORBA_sequence_set_release(retval, CORBA_TRUE); ++ ++ vptr = (CORBA_long *)retval->_buffer; ++ *vptr = poa->poaID; ++ memcpy(retval->_buffer + sizeof(CORBA_unsigned_long), poa->rand_data, ORBIT_RAND_KEY_LEN); ++ ++ vptr = (CORBA_long *)(retval->_buffer + POA_KEY_LEN); ++ if(obj) { ++ *vptr = obj->objnum; ++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), obj->rand_data, ORBIT_RAND_KEY_LEN); ++ } else { ++ *vptr = -((CORBA_long)oid->_length); ++ memcpy(retval->_buffer + POA_KEY_LEN + sizeof(CORBA_unsigned_long), oid->_buffer, oid->_length); ++ } ++} ++ ++ORBit_POAObject * ++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa, ++ CORBA_sequence_octet *object_key, ++ PortableServer_ObjectId **oid) ++{ ++ CORBA_long onum; ++ guchar *nptr; ++ ORBit_POAObject *objinfo; ++ ++ *oid = NULL; ++ nptr = object_key->_buffer + POA_KEY_LEN; ++ ++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long))) { ++ return NULL; ++ } ++ ++ onum = *((CORBA_long *)nptr); ++ ++ if(onum < 0) { ++ /* onum will be the -strlen(ObjectId) */ ++ if(object_key->_length < (POA_KEY_LEN + sizeof(CORBA_long) - onum)) ++ return NULL; ++ ++ *oid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ (*oid)->_length = -onum; ++ (*oid)->_buffer = CORBA_octet_allocbuf((*oid)->_length); ++ memcpy((*oid)->_buffer, object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), (*oid)->_length); ++ ++ return NULL; ++ } ++ ++ if(onum >= poa->objnum_to_obj->len) ++ return NULL; ++ ++ objinfo = g_ptr_array_index(poa->objnum_to_obj, onum); ++ ++ if(GPOINTER_TO_UINT(objinfo) <= poa->objnum_to_obj->len) ++ return NULL; ++ ++ if(object_key->_length < (POA_KEY_LEN + OBJ_KEY_LEN)) ++ return NULL; ++ ++ if(memcmp(object_key->_buffer + POA_KEY_LEN + sizeof(CORBA_long), objinfo->rand_data, ORBIT_RAND_KEY_LEN)) ++ return NULL; ++ ++ return objinfo; ++} ++ ++DEFINE_LOCK(id_assignment_counter); ++static int id_assignment_counter = 0; ++ ++PortableServer_ObjectId * ++ORBit_POA_allocate_oid(PortableServer_POA poa, ++ const char *basis) ++{ ++ PortableServer_ObjectId *new_objid; ++ char buf[512]; ++ int len; ++ ++ new_objid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ ++ GET_LOCK(id_assignment_counter); ++ g_snprintf(buf, sizeof(buf), "%s%d", basis?basis:"Object", ++ id_assignment_counter); ++ id_assignment_counter++; ++ RELEASE_LOCK(id_assignment_counter); ++ ++ len = strlen(buf)+1; ++ new_objid->_buffer = CORBA_octet_allocbuf(len); ++ new_objid->_length = len; ++ new_objid->_maximum = len; ++ new_objid->_release = CORBA_TRUE; ++ ++ strcpy((CORBA_char *)new_objid->_buffer, buf); ++ ++ return new_objid; ++} ++ ++static PortableServer_Servant ++ORBit_POA_ServantManager_use_servant(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer, ++ PortableServer_ServantLocator_Cookie *the_cookie, ++ PortableServer_ObjectId *oid, ++ ORBit_POAObject *fake_obj_impl, ++ CORBA_Environment *ev) ++{ ++ if(poa->servant_retention == PortableServer_RETAIN) { ++ POA_PortableServer_ServantActivator *sm; ++ POA_PortableServer_ServantActivator__epv *epv; ++ ++ sm = (POA_PortableServer_ServantActivator *)poa->servant_manager; ++ epv = sm->vepv->PortableServer_ServantActivator_epv; ++ return epv->incarnate(sm, oid, poa, ev); ++ } else { ++ POA_PortableServer_ServantLocator *sm; ++ POA_PortableServer_ServantLocator__epv *epv; ++ PortableServer_ServantBase *retval; ++ ++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager; ++ epv = sm->vepv->PortableServer_ServantLocator_epv; ++ retval = epv->preinvoke(sm, oid, ++ poa, recv_buffer->message.u.request.operation, ++ the_cookie, ++ ev); ++ ++ ((ORBit_ObjectKey *)retval->_private)->object = fake_obj_impl; ++ fake_obj_impl->object_id = oid; ++ fake_obj_impl->poa = poa; ++ fake_obj_impl->orb = poa->orb; ++ fake_obj_impl->objnum = -1; ++#ifdef NOT_BACKWARDS_COMPAT_0_4 ++ fake_obj_impl->use_count = NULL; ++ fake_obj_impl->death_callback = NULL; ++#endif ++ ++ return retval; ++ } ++} ++ ++static void ++ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant, ++ PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer, ++ PortableServer_ServantLocator_Cookie cookie, ++ PortableServer_ObjectId *oid, ++ ORBit_POAObject *fake_obj_impl, ++ CORBA_Environment *ev) ++{ ++ POA_PortableServer_ServantLocator *sm; ++ POA_PortableServer_ServantLocator__epv *epv; ++ ++ if(poa->servant_retention != PortableServer_NON_RETAIN) ++ return; ++ ++ sm = (POA_PortableServer_ServantLocator *)poa->servant_manager; ++ epv = sm->vepv->PortableServer_ServantLocator_epv; ++ ++ ((ORBit_ObjectKey *)((PortableServer_ServantBase *)servant)->_private)->object = NULL; ++ epv->postinvoke(sm, oid, ++ poa, recv_buffer->message.u.request.operation, ++ cookie, servant, ev); ++ ++} ++ ++typedef struct { ++ PortableServer_POA poa; ++ CORBA_Environment *ev; ++} EtherealizeInfo; ++ ++void ++ORBit_POA_etherealize_object(PortableServer_ObjectId *oid, ++ ORBit_POAObject *obj_impl, ++ EtherealizeInfo *ei) ++{ ++ POA_PortableServer_ServantActivator__epv *epv; ++ POA_PortableServer_ServantActivator *sm; ++ ++ g_assert(ei->poa->servant_manager); ++ ++ g_hash_table_remove(ei->poa->active_object_map, ++ obj_impl->object_id); ++ ++ sm = (POA_PortableServer_ServantActivator *)ei->poa->servant_manager; ++ epv = sm->vepv->PortableServer_ServantActivator_epv; ++ epv->etherealize(sm, obj_impl->object_id, ei->poa, ++ obj_impl->servant, ++ CORBA_TRUE, CORBA_FALSE, ei->ev); ++} ++ ++void ++ORBit_POA_etherealize_objects(PortableServer_POA poa, ++ CORBA_Environment *ev) ++{ ++ EtherealizeInfo ei; ++ ++ ei.poa = poa; ++ ei.ev = ev; ++ ++ if(poa->servant_retention == PortableServer_RETAIN ++ && poa->request_processing == PortableServer_USE_SERVANT_MANAGER) { ++ ++ g_hash_table_foreach(poa->active_object_map, ++ (GHFunc)ORBit_POA_etherealize_object, ++ &ei); ++ } ++} ++ ++#ifdef NOT_BACKWARDS_COMPAT_0_4 ++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant, ++ int *use_count, ++ GFunc death_func, ++ gpointer user_data) ++{ ++ ORBit_POAObject *pobj; ++ ++ pobj = ORBIT_OBJECT_KEY(servant->_private)->object; ++ ++ pobj->use_count = use_count; ++ pobj->death_callback = death_func; ++ pobj->user_data = user_data; ++} ++#endif +diff -urN linux-2.4.1/net/korbit/orb/orbit_poa.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h +--- linux-2.4.1/net/korbit/orb/orbit_poa.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,89 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Phil Dawes <philipd@parallax.co.uk> ++ * ++ */ ++ ++/* ++ * ORBit specific POA funcitons. ++ * ++ */ ++ ++#ifndef _ORBIT_ORBIT_POA_H_ ++#define _ORBIT_ORBIT_POA_H_ ++ ++#include "orbit_types.h" ++#include "orbit_poa_type.h" ++ ++/* ++ * Creates a new POAManager ++ */ ++ ++extern PortableServer_POAManager ORBit_POAManager_new(CORBA_Environment *ev); ++ ++extern void ORBit_POAManager_free(PortableServer_POAManager poa_mgr, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POA ORBit_POA_new(CORBA_ORB orb, ++ CORBA_char *adapter_name, ++ PortableServer_POAManager the_POAManager, ++ CORBA_PolicyList *policies, ++ CORBA_Environment *ev); ++ ++extern void ORBit_POA_free(PortableServer_POA poa, CORBA_Environment *ev); ++ ++extern void ORBit_POA_add_child(PortableServer_POA poa, ++ PortableServer_POA child_poa, ++ CORBA_Environment *ev); ++void ORBit_POA_remove_child(PortableServer_POA poa, ++ PortableServer_POA child_poa, ++ CORBA_Environment *ev); ++ ++gboolean ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer, ++ PortableServer_POA poa); ++PortableServer_POA ++ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa, ++ CORBA_sequence_octet *key); ++void ++ORBit_POA_find_object_key_for_oid(PortableServer_POA poa, ++ ORBit_POAObject *obj, ++ PortableServer_ObjectId *oid, ++ CORBA_sequence_octet *retval); ++ORBit_POAObject * ++ORBit_POA_find_oid_for_object_key(PortableServer_POA poa, ++ CORBA_sequence_octet *object_key, ++ PortableServer_ObjectId **oid); ++ ++PortableServer_ObjectId *ORBit_POA_allocate_oid(PortableServer_POA poa, ++ const char *basis); ++ ++void ORBit_POA_etherealize_objects(PortableServer_POA poa, CORBA_Environment *ev); ++ ++#ifdef NOT_BACKWARDS_COMPAT_0_4 ++/* Bad hack for shared libraries */ ++void ORBit_servant_set_deathwatch(PortableServer_ServantBase *servant, ++ int *use_count, ++ GFunc death_func, ++ gpointer user_data); ++#endif ++ ++#endif /* !_ORBIT_ORBIT_POA_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_poa_type.h linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h +--- linux-2.4.1/net/korbit/orb/orbit_poa_type.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_poa_type.h Thu Feb 1 11:47:13 2001 +@@ -0,0 +1,112 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Phil Dawes <philipd@parallax.co.uk> ++ * ++ */ ++ ++/* ++ * ORBit specific POA funcitons. ++ * ++ */ ++ ++#ifndef _ORBIT_ORBIT_POA_TYPE_H_ ++#define _ORBIT_ORBIT_POA_TYPE_H_ ++ ++typedef void (*ORBitSkeleton)(PortableServer_ServantBase *_ORBIT_servant, ++ gpointer _ORBIT_recv_buffer, ++ CORBA_Environment *ev, ++ gpointer implementation); ++typedef ORBitSkeleton (*ORBit_impl_finder)(PortableServer_ServantBase *servant, ++ gpointer _ORBIT_recv_buffer, ++ gpointer *implementation); ++typedef void (*ORBit_local_objref_init)(CORBA_Object obj, ++ PortableServer_ServantBase *servant); ++typedef struct { ++ ORBit_impl_finder relay_call; ++ const gchar *class_name; ++ ORBit_local_objref_init init_local_objref; ++} PortableServer_ClassInfo; ++ ++#define ORBIT_RAND_KEY_LEN 8 ++ ++typedef struct { ++ PortableServer_ObjectId *object_id; ++ PortableServer_Servant servant; ++ PortableServer_POA poa; ++ CORBA_ORB orb; ++ CORBA_unsigned_long objnum; ++ ++ /* Stuff for doing shared libraries nicely */ ++ guchar rand_data[ORBIT_RAND_KEY_LEN]; ++ ++#ifdef NOT_BACKWARDS_COMPAT_0_4 ++ int *use_count; ++ GFunc death_callback; ++ gpointer user_data; ++#endif ++} ORBit_POAObject; ++ ++typedef struct { ++ PortableServer_ClassInfo *class_info; ++ ORBit_POAObject *object; ++} ORBit_ObjectKey; ++ ++#define ORBIT_OBJECT_KEY(x) ((ORBit_ObjectKey *)(x)) ++ ++struct PortableServer_POA_type { ++ struct ORBit_PseudoObject_struct parent; ++ ++ PortableServer_POA parent_poa; ++ CORBA_ORB orb; ++ CORBA_unsigned_long poaID; ++ ++ GHashTable *active_object_map; ++ GPtrArray *objnum_to_obj; /* maps objnums to ORBit_POAObject's */ ++ CORBA_long first_free_id; ++ ++ /* Requests received while in a HOLDING state */ ++ GSList *held_requests; ++ ++ /* this'll be a hash table when I can be arsed to look up ++ how to implement efficient hash tables - Phil.*/ ++ GSList *child_POAs; ++ ++ CORBA_char *the_name; ++ PortableServer_POAManager the_POAManager; ++ ++ PortableServer_AdapterActivator the_activator; ++ ++ PortableServer_ServantManager servant_manager; ++ PortableServer_Servant default_servant; ++ ++ PortableServer_ThreadPolicyValue thread; ++ PortableServer_LifespanPolicyValue lifespan; ++ PortableServer_IdUniquenessPolicyValue id_uniqueness; ++ PortableServer_IdAssignmentPolicyValue id_assignment; ++ PortableServer_ImplicitActivationPolicyValue implicit_activation; ++ PortableServer_ServantRetentionPolicyValue servant_retention; ++ PortableServer_RequestProcessingPolicyValue request_processing; ++ ++ guchar rand_data[ORBIT_RAND_KEY_LEN]; ++}; ++ ++#endif /* !_ORBIT_ORBIT_POA_TYPE_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.c linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c +--- linux-2.4.1/net/korbit/orb/orbit_typecode.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.c Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,593 @@ ++#include "orbit.h" ++#include "orbit_typecode.h" ++#include "cdr.h" ++#include "corba_typecode_type.h" ++#include <IIOP/giop-msg-buffer.h> ++#include "../IIOP/iiop-endianP.h" ++ ++#if 0 ++#define CORBA_Object_release(x, y) ({ g_message(__FILE__ ":%d Releasing object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_release(x, y); }) ++#define CORBA_Object_duplicate(x, y) ({ g_message(__FILE__ ":%d Duping object %#x from %d", __LINE__, \ ++x, ORBIT_ROOT_OBJECT(x)->refs); CORBA_Object_duplicate(x, y); }) ++#endif ++ ++typedef struct{ ++ CORBA_TypeCode tc; ++ guint index; ++}TCRecursionNode; ++ ++typedef struct{ ++ GSList* prior_tcs; /* Could be a hash table by typecode */ ++ guint current_idx; /* The "top-level" index of the start of the current codec */ ++}TCEncodeContext; ++ ++typedef struct{ ++ GSList* prior_tcs; /* Could be a hash table by offset */ ++ guint current_idx; ++}TCDecodeContext; ++ ++ ++ ++static void tc_enc(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx); ++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx); ++ ++ ++ ++typedef void ++(*CORBA_TypeCodeEncoder)(CORBA_TypeCode t, ++ CDR_Codec* c, ++ TCEncodeContext* ctx); ++ ++typedef void ++(*CORBA_TypeCodeDecoder)(CORBA_TypeCode t, ++ CDR_Codec* c, ++ TCDecodeContext* ctx); ++ ++ ++typedef enum{ ++ TK_EMPTY, ++ TK_SIMPLE, ++ TK_COMPLEX ++} TkType; ++ ++typedef struct{ ++ TkType type; ++ CORBA_TypeCodeEncoder encoder; ++ CORBA_TypeCodeDecoder decoder; ++} TkInfo; ++ ++static const TkInfo tk_info[CORBA_tk_last]={ ++ {TK_EMPTY, NULL, NULL}, /* tk_null */ ++ {TK_EMPTY, NULL, NULL}, /* tk_void */ ++ {TK_EMPTY, NULL, NULL}, /* tk_short */ ++ {TK_EMPTY, NULL, NULL}, /* tk_long */ ++ {TK_EMPTY, NULL, NULL}, /* tk_ushort */ ++ {TK_EMPTY, NULL, NULL}, /* tk_ulong */ ++ {TK_EMPTY, NULL, NULL}, /* tk_float */ ++ {TK_EMPTY, NULL, NULL}, /* tk_double */ ++ {TK_EMPTY, NULL, NULL}, /* tk_boolean */ ++ {TK_EMPTY, NULL, NULL}, /* tk_char */ ++ {TK_EMPTY, NULL, NULL}, /* tk_octet */ ++ {TK_EMPTY, NULL, NULL}, /* tk_any */ ++ {TK_EMPTY, NULL, NULL}, /* tk_TypeCode */ ++ {TK_EMPTY, NULL, NULL}, /* tk_Principal */ ++ {TK_COMPLEX, tc_enc_tk_objref, tc_dec_tk_objref}, /* tk_objref */ ++ {TK_COMPLEX, tc_enc_tk_struct, tc_dec_tk_struct}, /* tk_struct */ ++ {TK_COMPLEX, tc_enc_tk_union, tc_dec_tk_union}, /* tk_union */ ++ {TK_COMPLEX, tc_enc_tk_enum, tc_dec_tk_enum}, /* tk_enum */ ++ {TK_SIMPLE, tc_enc_tk_string, tc_dec_tk_string}, /* tk_string */ ++ {TK_COMPLEX, tc_enc_tk_sequence, tc_dec_tk_sequence}, /* tk_sequence */ ++ {TK_COMPLEX, tc_enc_tk_array, tc_dec_tk_array}, /* tk_array */ ++ {TK_COMPLEX, tc_enc_tk_alias, tc_dec_tk_alias}, /* tk_alias */ ++ {TK_COMPLEX, tc_enc_tk_except, tc_dec_tk_except}, /* tk_except */ ++ {TK_EMPTY, NULL, NULL}, /* tk_longlong */ ++ {TK_EMPTY, NULL, NULL}, /* tk_ulonglong */ ++ {TK_EMPTY, NULL, NULL}, /* tk_longdouble */ ++ {TK_EMPTY, NULL, NULL}, /* tk_wchar */ ++ {TK_SIMPLE, tc_enc_tk_wstring, tc_dec_tk_wstring}, /* tk_wstring */ ++ {TK_SIMPLE, tc_enc_tk_fixed, tc_dec_tk_fixed} /* tk_fixed */ ++}; ++ ++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode t, GIOPSendBuffer* buf) ++{ ++ CDR_Codec codec_d; ++ CDR_Codec* codec = &codec_d; ++ TCEncodeContext ctx; ++ GSList* l; ++ CORBA_octet codecbuf[2048]; ++ ++ CDR_codec_init_static(codec); ++ ++ codec->wptr = 0; ++ codec->buffer = codecbuf; ++ codec->release_buffer = FALSE; ++ codec->buf_len = 2048; ++ codec->data_endian=FLAG_ENDIANNESS; ++ ++ ctx.current_idx=0; ++ ctx.prior_tcs=NULL; ++ tc_enc(t, codec, &ctx); ++ for(l=ctx.prior_tcs;l;l=l->next) ++ g_free(l->data); ++ g_slist_free(ctx.prior_tcs); ++ giop_send_buffer_append_mem_indirect(buf, ++ codec->buffer, ++ codec->wptr); ++} ++ ++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* t, GIOPRecvBuffer* buf) ++{ ++ CDR_Codec codec_d; ++ CDR_Codec* codec = &codec_d; ++ TCDecodeContext ctx; ++ GSList* l; ++ ++ CDR_codec_init_static(codec); ++ codec->buffer=buf->cur; ++ codec->release_buffer=CORBA_FALSE; ++ codec->readonly=CORBA_TRUE; ++ codec->buf_len = /* hope this is correct */ ++ ((guchar *)buf->message_body) + ++ GIOP_MESSAGE_BUFFER(buf)->message_header.message_size ++ - ((guchar *)buf->cur); ++ ++ codec->data_endian=GIOP_MESSAGE_BUFFER(buf)->message_header.flags & 1; ++ ++ ctx.current_idx=0; ++ ctx.prior_tcs=NULL; ++ tc_dec(t, codec, &ctx); ++ for(l=ctx.prior_tcs;l;l=l->next) ++ g_free(l->data); ++ g_slist_free(ctx.prior_tcs); ++ buf->cur = ((guchar *)buf->cur) + codec->rptr; ++} ++ ++ ++/* Encode a typecode to a codec, possibly recursively */ ++ ++static void tc_enc(CORBA_TypeCode tc, ++ CDR_Codec* codec, ++ TCEncodeContext* ctx) ++{ ++ TCRecursionNode* node; ++ const TkInfo* info; ++ GSList* l; ++ CORBA_octet codecbuf[2048]; ++ CDR_Codec encaps_d; ++ CDR_Codec* encaps = &encaps_d; ++ ++ g_assert(CLAMP(0, tc->kind, CORBA_tk_last) == tc->kind); ++ ++ for(l=ctx->prior_tcs;l;l=l->next){ ++ TCRecursionNode* node=l->data; ++ /* CORBA_CORBA_TypeCode_equal might save space, but is slow.. */ ++ if(node->tc==tc){ ++ CDR_put_ulong(codec, CORBA_tk_recursive); ++ CDR_put_long(codec, ++ node->index ++ -ctx->current_idx ++ -codec->wptr); ++ return; ++ } ++ } ++ ++ /* All right, this isn't a previously met type. So record it. */ ++ /* NOTE: put kind before recording index so alignment is dealt with! */ ++ CDR_put_ulong(codec, tc->kind); ++ ++ node=g_new(TCRecursionNode, 1); ++ node->tc=tc; ++ node->index=ctx->current_idx+codec->wptr - 4; /* -4 for kind */ ++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node); ++ ++ info=&tk_info[tc->kind]; ++ switch(info->type){ ++ guint tmp_index; ++ case TK_EMPTY: ++ break; ++ case TK_COMPLEX: ++ tmp_index=ctx->current_idx; ++ ctx->current_idx+=codec->wptr+4; /* +4 for the length */ ++ CDR_codec_init_static(encaps); ++ encaps->wptr = 0; ++ encaps->buffer = codecbuf; ++ encaps->release_buffer = FALSE; ++ encaps->buf_len = 2048; ++ encaps->data_endian=FLAG_ENDIANNESS; ++ CDR_put_octet(encaps, FLAG_ENDIANNESS); ++ (info->encoder)(tc, encaps, ctx); ++ CDR_put_ulong(codec, encaps->wptr); ++ /* Now this is a time hog */ ++ CDR_put_octets(codec, encaps->buffer, encaps->wptr); ++ ctx->current_idx=tmp_index; ++ break; ++ case TK_SIMPLE: ++ (info->encoder)(tc, codec, ctx); ++ } ++} ++ ++static void ++ORBit_TypeCode_release(gpointer obj, CORBA_Environment *ev) ++{ ++ /* we will initialize the TC_ constants with a negative refcount */ ++ if(ORBIT_ROOT_OBJECT(obj)->refs >= 0) { ++ ORBIT_ROOT_OBJECT_UNREF(obj); ++ ++ if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) { ++ CORBA_TypeCode tc = obj; ++ int i; ++ ++ g_free(tc->name); ++ g_free(tc->repo_id); ++ ++ for(i = 0; i < tc->sub_parts; i++) { ++ if(tc->subnames) ++ g_free(tc->subnames[i]); ++ ++ if(tc->subtypes) ++ CORBA_Object_release((CORBA_Object)tc->subtypes[i], ev); ++ ++ if(tc->sublabels) ++ CORBA_any__free(&tc->sublabels[i], NULL, TRUE); ++ } ++ ++ g_free(tc->subnames); ++ g_free(tc->subtypes); ++ g_free(tc->sublabels); ++ ++ if(tc->discriminator) ++ CORBA_Object_release((CORBA_Object)tc->discriminator, ev); ++ ++ g_free(obj); ++ } ++ ++ } ++} ++ ++const ORBit_RootObject_Interface ORBit_TypeCode_epv = { ++ &ORBit_TypeCode_release ++}; ++ ++static void tc_dec(CORBA_TypeCode* t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CORBA_TCKind kind; ++ CORBA_TypeCode tc; ++ const TkInfo* info; ++ TCRecursionNode* node; ++ CDR_Codec encaps_d; ++ CDR_Codec* encaps = &encaps_d; ++ ++ CDR_get_ulong(c, &kind); ++ ++ g_assert(CLAMP(0, kind, CORBA_tk_last) == kind); ++ ++ if(kind==CORBA_tk_recursive){ ++ CORBA_long offset; ++ GSList* l; ++ CDR_get_ulong(c, &offset); ++ for(l=ctx->prior_tcs;l;l=l->next){ ++ node=l->data; ++ /* NOTE: below, -4 is b/c we already read offset */ ++ if(node->index==ctx->current_idx+c->rptr+offset-4){ ++ *t=node->tc; ++ return; ++ } ++ } ++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error, ++ "tc_dec: Invalid CORBA_TypeCode recursion offset " ++ "in input buffer\n"); ++ g_assert_not_reached(); ++ } ++ ++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "codec->host_endian: %d, codec->data_endian: %d\n", c->host_endian, c->data_endian); ++ ORBit_Trace(TraceMod_TC, TraceLevel_Debug, "kind: %d, CORBA_tk_last: %d\n", kind, CORBA_tk_last); ++ g_assert(kind<CORBA_tk_last); ++ ++ node=g_new(TCRecursionNode, 1); ++ node->index=ctx->current_idx+c->rptr-4; /* -4 for the TCKind */ ++ info=&tk_info[kind]; ++ ++ tc=g_new0(struct CORBA_TypeCode_struct, 1); ++ ++ /* Passing in NULL for CORBA_Environment is patently dangerous. */ ++ ORBit_pseudo_object_init((ORBit_PseudoObject)tc, ++ ORBIT_PSEUDO_TYPECODE, NULL); ++ ORBit_RootObject_set_interface((ORBit_RootObject)tc, ++ (ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, ++ NULL); ++ ++ tc->kind=kind; ++ switch(info->type){ ++ guint tmp_index; ++ CORBA_octet o; ++ ++ case TK_EMPTY: ++ break; ++ ++ case TK_COMPLEX: ++ tmp_index=ctx->current_idx; ++ CDR_codec_init_static(encaps); ++ CDR_get_ulong(c, &encaps->buf_len); ++ ctx->current_idx+=c->rptr; ++ encaps->buffer=&c->buffer[c->rptr]; ++ encaps->release_buffer=CORBA_FALSE; ++ CDR_get_octet(encaps, &o); ++ encaps->data_endian=o; ++ (info->decoder)(tc, encaps, ctx); ++ c->rptr += encaps->buf_len; ++ ctx->current_idx=tmp_index; ++ break; ++ case TK_SIMPLE: ++ (info->decoder)(tc, c, ctx); ++ break; ++ } ++ node->tc=tc; ++ ctx->prior_tcs=g_slist_prepend(ctx->prior_tcs, node); ++ *t=tc; ++} ++ ++ ++ ++static void tc_enc_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++} ++ ++static void tc_dec_tk_objref(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++} ++ ++static void tc_enc_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ tc_enc(*t->subtypes, c, ctx); ++ CDR_put_ulong(c, t->length); ++} ++ ++static void tc_dec_tk_sequence(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ t->subtypes=g_new(CORBA_TypeCode, 1); ++ tc_dec(&t->subtypes[0], c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL); ++ CDR_get_ulong(c, &t->length); ++} ++ ++static void tc_enc_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CDR_put_ulong(c, t->length); ++} ++ ++static void tc_dec_tk_string(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CDR_get_ulong(c, &t->length); ++} ++ ++static void tc_enc_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++ CDR_put_ulong(c, t->sub_parts); ++ for(i=0;i<t->sub_parts;i++){ ++ CDR_put_string(c, t->subnames[i]); ++ tc_enc(t->subtypes[i], c, ctx); ++ } ++} ++ ++static void tc_dec_tk_struct(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++ CDR_get_ulong(c, &t->sub_parts); ++ t->subnames=g_new(gchar*, t->sub_parts); ++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts); ++ for(i=0;i<t->sub_parts;i++){ ++ CDR_get_string(c, &t->subnames[i]); ++ tc_dec(&t->subtypes[i], c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL); ++ } ++} ++ ++#define UNION_MEMBERS(dir) \ ++ MEMBER_LOOPER_##dir(ulong, long, long); \ ++ case CORBA_tk_enum: /* fall through */ \ ++ MEMBER_LOOPER_##dir(ulong, unsigned_long, ulong); \ ++ MEMBER_LOOPER_##dir(octet, boolean, boolean); \ ++ MEMBER_LOOPER_##dir(octet, char, char); \ ++ MEMBER_LOOPER_##dir(ushort, short, short); \ ++ MEMBER_LOOPER_##dir(ushort, unsigned_short, ushort); \ ++ MEMBER_LOOPER_##dir(ulong_long, long_long, longlong); \ ++ MEMBER_LOOPER_##dir(ulong_long, unsigned_long_long, ulonglong); \ ++ /* MEMBER_LOOPER_##dir(wchar, wchar, wchar); */ ++ ++ ++static void tc_enc_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++ tc_enc(t->discriminator, c, ctx); ++ CDR_put_long(c, t->default_index); ++ CDR_put_ulong(c, t->sub_parts); ++ i=t->sub_parts; ++ /* Thank goodness the discriminator types are rather limited, ++ we can do the marshalling inline.. */ ++#define MEMBER_LOOPER_ENC(putname, typename, tkname) \ ++ case CORBA_tk_##tkname: \ ++ for(i=0;i<t->sub_parts;i++){ \ ++ CDR_put_##putname(c, *(CORBA_##typename*) \ ++ (t->sublabels[i]._value)); \ ++ CDR_put_string(c, t->subnames[i]); \ ++ tc_enc(t->subtypes[i], c, ctx); \ ++ } \ ++ break ++ ++ switch(t->discriminator->kind){ ++ UNION_MEMBERS(ENC); ++ default: ++ ORBit_Trace(TraceMod_ORB, TraceLevel_Error, ++ "tc_enc_tk_union: Illegal union discriminator " ++ "type %s\n", t->discriminator->name); ++ } ++} ++ ++static void tc_dec_tk_union(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++ tc_dec(&t->discriminator, c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL); ++ CDR_get_ulong(c, &t->default_index); ++ CDR_get_ulong(c, &t->sub_parts); ++ ++ t->sublabels=g_new(CORBA_any, t->sub_parts); ++ t->subnames=g_new(gchar*, t->sub_parts); ++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts); ++ ++#define MEMBER_LOOPER_DEC(getname, typename, tkname) \ ++ case CORBA_tk_##tkname: \ ++ for(i=0;i<t->sub_parts;i++){ \ ++ t->sublabels[i]._type = \ ++ CORBA_Object_duplicate((CORBA_Object)t->discriminator, NULL); \ ++ t->sublabels[i]._value = g_new(CORBA_##typename,1); \ ++ t->sublabels[i]._release = CORBA_TRUE; \ ++ CDR_get_##getname(c, t->sublabels[i]._value); \ ++ CDR_get_string(c, &t->subnames[i]); \ ++ tc_dec(&t->subtypes[i], c, ctx); \ ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL); \ ++ } \ ++ break ++ ++ switch(t->discriminator->kind){ ++ UNION_MEMBERS(DEC); ++ default: ++ /* XXX: what is correct error handling */ ++ g_assert(!"Not yet implemented."); ++ } ++} ++ ++static void tc_enc_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++ CDR_put_ulong(c, t->sub_parts); ++ for(i=0;i<t->sub_parts;i++) ++ CDR_put_string(c, t->subnames[i]); ++} ++ ++static void tc_dec_tk_enum(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CORBA_unsigned_long i; ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++ CDR_get_ulong(c, &t->sub_parts); ++ t->subnames=g_new(gchar*, t->sub_parts); ++ for(i=0;i<t->sub_parts;i++) ++ CDR_get_string(c, &t->subnames[i]); ++} ++ ++static void tc_enc_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++ tc_enc(*t->subtypes, c, ctx); ++} ++ ++static void tc_dec_tk_alias(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++ t->subtypes=g_new(CORBA_TypeCode, 1); ++ tc_dec(t->subtypes, c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL); ++} ++ ++ ++static void tc_enc_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ gulong i; ++ CDR_put_string(c, t->repo_id); ++ CDR_put_string(c, t->name); ++ CDR_put_ulong(c, t->sub_parts); ++ for(i=0;i<t->length;i++){ ++ CDR_put_string(c, t->subnames[i]); ++ tc_enc(t->subtypes[i], c, ctx); ++ } ++} ++ ++static void tc_dec_tk_except(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ gulong i; ++ CDR_get_string(c, &t->repo_id); ++ CDR_get_string(c, &t->name); ++ CDR_get_ulong(c, &t->sub_parts); ++ t->subtypes=g_new(CORBA_TypeCode, t->sub_parts); ++ t->subnames=g_new(gchar*, t->sub_parts); ++ for(i=0;i<t->length;i++){ ++ CDR_get_string(c, &t->subnames[i]); ++ tc_dec(&t->subtypes[i], c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[i], NULL); ++ } ++} ++ ++static void tc_enc_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ tc_enc(*t->subtypes, c, ctx); ++ CDR_put_ulong(c, t->length); ++} ++ ++static void tc_dec_tk_array(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ t->subtypes=g_new(CORBA_TypeCode, 1); ++ tc_dec(t->subtypes, c, ctx); ++ CORBA_Object_duplicate((CORBA_Object)t->subtypes[0], NULL); ++ CDR_get_ulong(c, &t->length); ++} ++ ++static void tc_enc_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ g_assert(!"Not yet implemented."); ++} ++ ++static void tc_dec_tk_wstring(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ g_assert(!"Not yet implemented."); ++} ++ ++static void tc_enc_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCEncodeContext* ctx) ++{ ++ g_assert(!"Not yet implemented."); ++} ++ ++static void tc_dec_tk_fixed(CORBA_TypeCode t, CDR_Codec* c, TCDecodeContext* ctx) ++{ ++ g_assert(!"Not yet implemented."); ++} +diff -urN linux-2.4.1/net/korbit/orb/orbit_typecode.h linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h +--- linux-2.4.1/net/korbit/orb/orbit_typecode.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_typecode.h Thu Feb 1 16:21:53 2001 +@@ -0,0 +1,10 @@ ++#ifndef _ORBIT_ORBIT_TYPECODE_H_ ++#define _ORBIT_ORBIT_TYPECODE_H_ ++ ++#include "orbit_types.h" ++ ++extern const ORBit_RootObject_Interface ORBit_TypeCode_epv; ++void ORBit_encode_CORBA_TypeCode(CORBA_TypeCode tc, GIOPSendBuffer* buf); ++void ORBit_decode_CORBA_TypeCode(CORBA_TypeCode* tc, GIOPRecvBuffer* buf); ++ ++#endif +diff -urN linux-2.4.1/net/korbit/orb/orbit_types.h linux-2.4.1-korbit/net/korbit/orb/orbit_types.h +--- linux-2.4.1/net/korbit/orb/orbit_types.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/orbit_types.h Thu Feb 1 16:20:50 2001 +@@ -0,0 +1,176 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_TYPES_H_ ++#define _ORBIT_TYPES_H_ ++ ++#include <stddef.h> /* for wchar_t */ ++#include <sys/types.h> /* for sysdep types */ ++#include <netinet/in.h> /* for sockaddr_in */ ++#include <sys/uio.h> /* for struct iovec */ ++ ++#include <ORBitutil/basic_types.h> ++ ++#define CORBA_TRUE 1 ++#define CORBA_FALSE 0 ++ ++typedef CORBA_char *CORBA_ORBid; ++ ++typedef CORBA_unsigned_long CORBA_ServiceOption; ++typedef CORBA_unsigned_long CORBA_ServiceDetailType; ++ ++#include "corba_orb.h" ++ ++/* ++ * CORBA_RepositoryId and CORBA_Identifier are defined in the Interface ++ * Repository, but are needed in other interfaces in the ORB itself. ++ */ ++#if !defined(_CORBA_Identifier_defined) ++#define _CORBA_Identifier_defined 1 ++typedef CORBA_char *CORBA_Identifier; ++#define CORBA_Identifier__free CORBA_string__free ++#endif ++ ++#if !defined(_CORBA_RepositoryId_defined) ++#define _CORBA_RepositoryId_defined 1 ++typedef CORBA_char *CORBA_RepositoryId; ++#define CORBA_RepositoryId__free CORBA_string__free ++#endif ++ ++#include "corba_any.h" ++ ++typedef struct CORBA_ServiceDetail_type CORBA_ServiceDetail; ++typedef struct CORBA_Request_type *CORBA_Request; ++typedef struct CORBA_ServerRequest_type *CORBA_ServerRequest; ++typedef struct CORBA_DynFixed_type *CORBA_DynFixed; ++typedef struct CORBA_Current_type *CORBA_Current; ++typedef void CORBA_Status; ++typedef CORBA_unsigned_long CORBA_enum; ++typedef CORBA_unsigned_long CORBA_Flags; ++ ++typedef struct CORBA_NVList_type { ++ CORBA_Flags flags; ++ GArray *list; ++} CORBA_NVList; ++ ++#include "corba_context.h" ++ ++#include "corba_portableserver.h" ++ ++#include "corba_env.h" ++ ++#include "corba_sequences_type.h" ++ ++#include "corba_basic_sequences_type.h" ++ ++#include "corba_object.h" ++ ++#include "orbit_object_type.h" ++ ++#include "corba_object_type.h" ++ ++#include "corba_orb_type.h" ++ ++#include "corba_typecode.h" ++#include "corba_typecode_type.h" ++#include "corba_any_type.h" ++#include "corba_any_proto.h" ++ ++#if !defined(TC_IMPL_TC_CORBA_Identifier_0) ++#define TC_IMPL_TC_CORBA_Identifier_0 '/' ++#define TC_CORBA_Identifier ((CORBA_TypeCode)&TC_CORBA_Identifier_struct) ++extern const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct; ++#endif ++ ++#if !defined(TC_IMPL_TC_CORBA_RepositoryId_0) ++#define TC_IMPL_TC_CORBA_RepositoryId_0 '/' ++extern const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct; ++#define TC_CORBA_RepositoryId ((CORBA_TypeCode)&TC_CORBA_RepositoryId_struct) ++#endif ++ ++/* 19.14 */ ++ ++/* XXX */ ++typedef struct CORBA_fixed_d_s { ++ CORBA_unsigned_short _digits; ++ CORBA_short _scale; ++ signed char _sign; ++ signed char _value[1]; ++} CORBA_fixed_d_s; ++ ++#include "corba_env_type.h" ++ ++ ++typedef struct CORBA_WrongTransaction { ++ int dummy; ++} CORBA_WrongTransaction; ++ ++#define CORBA_ARG_IN (1<<0) ++#define CORBA_ARG_OUT (1<<1) ++#define CORBA_ARG_INOUT (1<<2) ++#define CORBA_CTX_RESTRICT_SCOPE (1<<3) ++#define CORBA_CTX_DELETE_DESCENDENTS (1<<4) ++#define CORBA_OUT_LIST_MEMORY (1<<5) ++#define CORBA_IN_COPY_VALUE (1<<6) ++#define CORBA_DEPENDENT_LIST (1<<7) ++#define CORBA_INV_NO_RESPONSE (1<<8) ++#define CORBA_INV_TERM_ON_ERROR (1<<9) ++#define CORBA_RESP_NO_WAIT (1<<10) ++ ++typedef struct CORBA_NamedValue { ++ CORBA_Identifier name; /* argument name */ ++ CORBA_any argument; /* argument */ ++ CORBA_long len; /* length/count of argument value */ ++ CORBA_Flags arg_modes; /* argument mode flags */ ++} CORBA_NamedValue; ++ ++typedef CORBA_char *CORBA_FieldName; ++ ++typedef struct CORBA_NameValuePair { ++ CORBA_FieldName id; ++ CORBA_any value; ++} CORBA_NameValuePair; ++ ++struct CORBA_Current_type { ++ int fill_me_in; ++}; ++ ++#include "corba_portableserver_type.h" ++ ++typedef CORBA_unsigned_short CORBA_ServiceType; ++ ++#define CORBA_Security (1) ++ ++struct CORBA_ServiceDetail_type { ++ CORBA_ServiceDetailType service_detail_type; ++ CORBA_sequence_octet service_detail; ++}; ++ ++typedef struct CORBA_ServiceInformation_struct { ++ CORBA_sequence_ServiceOption service_options; ++ CORBA_sequence_ServiceDetail service_details; ++} CORBA_ServiceInformation; ++ ++#endif /* !_ORBIT_TYPES_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/poa.c linux-2.4.1-korbit/net/korbit/orb/poa.c +--- linux-2.4.1/net/korbit/orb/poa.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/poa.c Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,1387 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter, and Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * Elliot Lee <sopwith@redhat.com> ++ * ++ */ ++ ++#include <string.h> ++#include <stdio.h> ++#include <assert.h> ++ ++#include "orbit.h" ++#include "orbit_poa.h" ++#include "genrand.h" ++ ++PortableServer_ThreadPolicyValue ++PortableServer_ThreadPolicy__get_value(PortableServer_ThreadPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ev->_major = CORBA_NO_EXCEPTION; ++ ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_LifespanPolicyValue ++PortableServer_LifespanPolicy__get_value(PortableServer_LifespanPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_IdUniquenessPolicyValue ++PortableServer_IdUniquenessPolicy__get_value(PortableServer_IdUniquenessPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_IdAssignmentPolicyValue ++PortableServer_IdAssignmentPolicy__get_value(PortableServer_IdAssignmentPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_ImplicitActivationPolicyValue ++PortableServer_ImplicitActivationPolicy__get_value(PortableServer_ImplicitActivationPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_ServantRetentionPolicyValue ++PortableServer_ServantRetentionPolicy__get_value(PortableServer_ServantRetentionPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++PortableServer_RequestProcessingPolicyValue ++PortableServer_RequestProcessingPolicy__get_value(PortableServer_RequestProcessingPolicy obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ ev->_major = 2 ; ++ goto error_exit; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->value; ++ ++error_exit: ++ CORBA_exception_set_system(ev, 0, CORBA_COMPLETED_NO); ++ return 0; ++} ++ ++/* make emacs happy; */ ++ ++PortableServer_POAManager_State ++PortableServer_POAManager_get_state(PortableServer_POAManager obj, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return -1; ++ } ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ return obj->state; ++} ++ ++/**** PortableServer_POAManager_activate ++ Inputs: 'obj' - a POAManager to activate ++ Outputs: '*ev' - result of the activate operation ++ ++ Side effect: Clears the 'held_requests' lists for all POA's ++ associated with the 'obj' POAManager. ++ ++ Description: Sets the POAManager state to 'ACTIVE', then ++ goes through all the POA's associated with this ++ POAManager, and makes them re-process their ++ 'held_requests' ++ */ ++void ++PortableServer_POAManager_activate(PortableServer_POAManager obj, ++ CORBA_Environment *ev) ++{ ++ GSList *todo; ++ GSList *curitem; ++ PortableServer_POA curpoa; ++ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->state == PortableServer_POAManager_INACTIVE) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POAManager_AdapterInactive, ++ NULL); ++ return; ++ } ++ ++ obj->state = PortableServer_POAManager_ACTIVE; ++ ++ for(curitem = obj->poa_collection; curitem; ++ curitem = g_slist_next(curitem)) { ++ curpoa = (PortableServer_POA)curitem->data; ++ ++ todo = curpoa->held_requests; ++ curpoa->held_requests = NULL; ++ ++ g_slist_foreach(todo, (GFunc)ORBit_POA_handle_request, ++ curpoa); ++ g_slist_foreach(todo, (GFunc)giop_recv_buffer_unuse, ++ NULL); ++ ++ g_slist_free(todo); ++ } ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++void ++PortableServer_POAManager_hold_requests(PortableServer_POAManager obj, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->state == PortableServer_POAManager_INACTIVE) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POAManager_AdapterInactive, ++ NULL); ++ return; ++ } ++ ++ obj->state = PortableServer_POAManager_HOLDING; ++ if(!wait_for_completion) ++ g_warning("hold_requests not finished - don't know how to kill outstanding request fulfillments"); ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++void ++PortableServer_POAManager_discard_requests(PortableServer_POAManager obj, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->state == PortableServer_POAManager_INACTIVE) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POAManager_AdapterInactive, ++ NULL); ++ return; ++ } ++ ++ obj->state = PortableServer_POAManager_DISCARDING; ++ if(!wait_for_completion) ++ g_warning("discard_requests not finished - don't know how to kill outstanding request fulfillments"); ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++void ++PortableServer_POAManager_deactivate(PortableServer_POAManager obj, ++ CORBA_boolean etherealize_objects, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->state == PortableServer_POAManager_INACTIVE) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POAManager_AdapterInactive, ++ NULL); ++ return; ++ } ++ ++ obj->state = PortableServer_POAManager_INACTIVE; ++ ++ if(etherealize_objects) ++ g_slist_foreach(obj->poa_collection, (GFunc)ORBit_POA_etherealize_objects, ev); ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++ ++CORBA_boolean ++PortableServer_AdapterActivator_unknown_adapter(PortableServer_AdapterActivator obj, ++ PortableServer_POA parent, ++ CORBA_char *name, ++ CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(CORBA_FALSE); ++} ++ ++ ++/**** PortableServer_ServantActivator_incarnate ++ */ ++PortableServer_Servant ++ ++PortableServer_ServantActivator_incarnate ++(PortableServer_ServantActivator obj, ++ PortableServer_ObjectId *oid, ++ PortableServer_POA adapter, ++ CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++void ++PortableServer_ServantActivator_etherealize ++(PortableServer_ServantActivator obj, ++ PortableServer_ObjectId *oid, PortableServer_POA adapter, ++ PortableServer_Servant serv, ++ CORBA_boolean cleanup_in_progress, ++ CORBA_boolean remaining_activations, ++ CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return; ++} ++ ++PortableServer_POA ++PortableServer_POA_create_POA ++ (PortableServer_POA poa, ++ CORBA_char *adapter_name, ++ PortableServer_POAManager a_POAManager, ++ CORBA_PolicyList* policies, ++ CORBA_Environment *ev) ++{ ++ PortableServer_POA new_poa = NULL; ++ PortableServer_POA check_poa = NULL; ++ ++ /* Check for a child POA by the same name in parent */ ++ check_poa = PortableServer_POA_find_POA(poa,adapter_name, ++ FALSE, ev); ++ CORBA_exception_free (ev); ++ ++ if (!check_poa) { ++ new_poa = ORBit_POA_new(poa->orb, ++ adapter_name, a_POAManager, policies, ev); ++ } else { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_AdapterAlreadyExists, ++ NULL); ++ new_poa = NULL; ++ } ++ ++ if(ev->_major == CORBA_NO_EXCEPTION) { ++ new_poa->parent_poa = poa; ++ ORBit_POA_add_child(poa, new_poa, ev); ++ } ++ ++ return new_poa; ++} ++ ++/**** PortableServer_POA_find_POA ++ Inputs: 'obj' - a POA ++ 'activate_it' - whether to activate unknown POA's ++ ++ Outputs: 'child_poa' ++ ++ Description: Finds (and optionally activates) a child POA of 'obj' ++ with the specified names. ++ ++ TODO: Activate non-existent adapters if asked. ++ ++ */ ++PortableServer_POA ++PortableServer_POA_find_POA(PortableServer_POA obj, ++ CORBA_char *adapter_name, ++ CORBA_boolean activate_it, ++ CORBA_Environment *ev) ++{ ++ GSList *curitem; ++ PortableServer_POA child_poa; ++ ++ for(curitem = obj->child_POAs; curitem; ++ curitem = g_slist_next(curitem)) { ++ child_poa = (PortableServer_POA)curitem->data; ++ if(!strcmp(child_poa->the_name, adapter_name)) { ++ ev->_major = CORBA_NO_EXCEPTION; ++ return child_poa; ++ } ++ } ++ ++ if(activate_it) ++ g_warning("Don't yet know how to activate POA named \"%s\"", ++ adapter_name); ++ ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_AdapterNonExistent, ++ NULL); ++ ++ return NULL; ++} ++ ++/**** PortableServer_POA_destroy ++ Inputs: 'obj' - the POA to be destroyed ++ 'etherealize_objects' - flag indicating whether any servant ++ manager should be asked to etherealize ++ objects in the active object map ++ 'wait_for_completion' - flag indicating whether to wait for ++ requests currently being handled ++ */ ++void ++PortableServer_POA_destroy(PortableServer_POA obj, ++ CORBA_boolean etherealize_objects, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev) ++{ ++ if(etherealize_objects || !wait_for_completion) ++ g_warning("PortableServer_POA_destroy not yet fully implemented; ignoring flags"); ++ ++ if(ORBIT_ROOT_OBJECT(obj)->refs > 1) ++ g_warning("POA has multiple refs [%d]", ++ ORBIT_ROOT_OBJECT(obj)->refs); ++ ++ CORBA_Object_release((CORBA_Object)obj, ev); ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy(PortableServer_POA obj, PortableServer_ThreadPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_ThreadPolicy retval; ++ ++ retval = g_new(struct PortableServer_ThreadPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_THREAD_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_ThreadPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy(PortableServer_POA obj, PortableServer_LifespanPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_LifespanPolicy retval; ++ ++ retval = g_new(struct PortableServer_LifespanPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_LIFESPAN_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_LifespanPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy(PortableServer_POA obj, PortableServer_IdUniquenessPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_IdUniquenessPolicy retval; ++ ++ retval = g_new(struct PortableServer_IdUniquenessPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_ID_UNIQUENESS_POLICY_ID, ++ ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_IdUniquenessPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy(PortableServer_POA obj, PortableServer_IdAssignmentPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_IdAssignmentPolicy retval; ++ ++ retval = g_new(struct PortableServer_IdAssignmentPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_ID_ASSIGNMENT_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_IdAssignmentPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy(PortableServer_POA obj, PortableServer_ImplicitActivationPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_ImplicitActivationPolicy retval; ++ ++ retval = g_new(struct PortableServer_ImplicitActivationPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_IMPLICIT_ACTIVATION_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_ImplicitActivationPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy(PortableServer_POA obj, PortableServer_ServantRetentionPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_ServantRetentionPolicy retval; ++ ++ retval = g_new(struct PortableServer_ServantRetentionPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_SERVANT_RETENTION_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_ServantRetentionPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy(PortableServer_POA obj, PortableServer_RequestProcessingPolicyValue value, CORBA_Environment *ev) ++{ ++ PortableServer_RequestProcessingPolicy retval; ++ ++ retval = g_new(struct PortableServer_RequestProcessingPolicy_type, 1); ++ ORBit_policy_object_init((CORBA_Policy)retval, ++ PortableServer_REQUEST_PROCESSING_POLICY_ID, ev); ++ ++ retval->value = value; ++ ++ return (PortableServer_RequestProcessingPolicy)CORBA_Object_duplicate((CORBA_Object)retval, ev); ++} ++ ++CORBA_char *PortableServer_POA__get_the_name(PortableServer_POA obj, CORBA_Environment *ev) ++{ ++ g_assert(obj); ++ g_assert(obj->the_name); ++ return obj->the_name; ++} ++ ++PortableServer_POA ++PortableServer_POA__get_the_parent(PortableServer_POA obj, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ return obj->parent_poa; ++} ++ ++PortableServer_POAManager ++PortableServer_POA__get_the_POAManager(PortableServer_POA obj, ++ CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ return obj->the_POAManager; ++} ++ ++PortableServer_AdapterActivator PortableServer_POA__get_the_activator(PortableServer_POA obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ return obj->the_activator; ++} ++ ++void PortableServer_POA__set_the_activator(PortableServer_POA obj, PortableServer_AdapterActivator the_activator, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ++ ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ obj->the_activator = the_activator; ++} ++ ++PortableServer_ServantManager PortableServer_POA_get_servant_manager(PortableServer_POA obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ return obj->servant_manager; ++} ++ ++void PortableServer_POA_set_servant_manager(PortableServer_POA obj, PortableServer_ServantManager imgr, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->request_processing != PortableServer_USE_SERVANT_MANAGER) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return; ++ } ++ ++ obj->servant_manager = imgr; ++} ++ ++PortableServer_Servant PortableServer_POA_get_servant(PortableServer_POA obj, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ return obj->default_servant; ++} ++ ++void PortableServer_POA_set_servant(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev) ++{ ++ if(!obj) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return; ++ } ++ ++ obj->default_servant = p_servant; ++} ++ ++static CORBA_unsigned_long ++get_objnum_for_obj(PortableServer_POA poa, ORBit_POAObject *obj) ++{ ++ CORBA_unsigned_long retval; ++ ++ if(poa->first_free_id) { ++ retval = poa->first_free_id; ++ poa->first_free_id = GPOINTER_TO_UINT(g_ptr_array_index(poa->objnum_to_obj, ++ retval)); ++ g_ptr_array_index(poa->objnum_to_obj, retval) = obj; ++ } else { ++ retval = poa->objnum_to_obj->len; ++ g_ptr_array_add(poa->objnum_to_obj, ++ obj); ++ } ++ ++ return retval; ++} ++ ++static CORBA_ORB ++get_orb_for_poa(PortableServer_POA poa) ++{ ++ if(poa->orb) ++ return poa->orb; ++ if(poa->parent_poa) ++ return get_orb_for_poa(poa->parent_poa); ++ ++ return CORBA_OBJECT_NIL; ++} ++ ++PortableServer_ObjectId * ++PortableServer_POA_activate_object(PortableServer_POA obj, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev) ++{ ++ PortableServer_ServantBase *servant; ++ PortableServer_ObjectId *new_objid; ++ ORBit_POAObject *new_obj; ++ ++ servant = p_servant; ++ ++ if(obj->servant_retention != PortableServer_RETAIN ++ || obj->id_assignment != PortableServer_SYSTEM_ID) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ /* Servant Already Active */ ++ if((obj->id_uniqueness==PortableServer_UNIQUE_ID) && ++ (ORBIT_OBJECT_KEY(servant->_private)->object != 0)) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_ServantAlreadyActive, ++ NULL); ++ return NULL; ++ } ++ ++ ++ new_obj = g_new0(ORBit_POAObject, 1); ++ new_obj->object_id = (PortableServer_ObjectId*)CORBA_sequence_octet__alloc(); ++ ++ new_objid = ++ ORBit_POA_allocate_oid(obj, ++ ORBIT_OBJECT_KEY(servant->_private)->class_info->class_name); ++ ++ new_obj->object_id->_buffer = CORBA_octet_allocbuf(new_objid->_length); ++ new_obj->object_id->_length = new_objid->_length; ++ memcpy(new_obj->object_id->_buffer, new_objid->_buffer, ++ new_objid->_length); ++ CORBA_sequence_set_release(new_obj->object_id, CORBA_TRUE); ++ ++ new_obj->servant = p_servant; ++ ORBIT_OBJECT_KEY(servant->_private)->object = new_obj; ++ new_obj->orb = get_orb_for_poa(obj); ++ new_obj->poa = obj; ++ new_obj->objnum = get_objnum_for_obj(obj, new_obj); ++ orbit_genrand(new_obj->rand_data, ORBIT_RAND_KEY_LEN); ++ ++ g_hash_table_insert(obj->active_object_map, ++ new_obj->object_id, ++ new_obj); ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++ ++ return new_objid; ++} ++ ++void ++PortableServer_POA_activate_object_with_id(PortableServer_POA obj, ++ PortableServer_ObjectId *id, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev) ++{ ++ PortableServer_ServantBase *servant = p_servant; ++ ORBit_POAObject *newobj; ++ ++ if(!obj || !id || !p_servant) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ newobj = g_hash_table_lookup(obj->active_object_map, ++ id); ++ ++ if(newobj) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_ObjectAlreadyActive, NULL); ++ return; ++ } ++ ++ newobj = g_new0(ORBit_POAObject, 1); ++ newobj->object_id = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ newobj->object_id->_length = id->_length; ++ newobj->object_id->_buffer = CORBA_octet_allocbuf(id->_length); ++ newobj->object_id->_release = CORBA_TRUE; ++ memcpy(newobj->object_id->_buffer, id->_buffer, id->_length); ++ newobj->poa = obj; ++ newobj->orb = get_orb_for_poa(obj); ++ newobj->objnum = get_objnum_for_obj(obj, newobj); ++ orbit_genrand(newobj->rand_data, ORBIT_RAND_KEY_LEN); ++ ++ newobj->servant = p_servant; ++ ++ g_hash_table_insert(obj->active_object_map, ++ newobj->object_id, ++ newobj); ++ ++ ORBIT_OBJECT_KEY(servant->_private)->object = newobj; ++ ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++void ++PortableServer_POA_deactivate_object(PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_Environment *ev) ++{ ++ ORBit_POAObject *oldobj; ++ ++ if(!obj || !oid) { ++ CORBA_exception_set_system(ev, ex_CORBA_BAD_PARAM, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ oldobj = g_hash_table_lookup(obj->active_object_map, ++ oid); ++ ++ if(!oldobj) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_ObjectNotActive, ++ NULL); ++ return; ++ } ++ ++ g_ptr_array_index(obj->objnum_to_obj, oldobj->objnum) = GUINT_TO_POINTER(obj->first_free_id); ++ obj->first_free_id = oldobj->objnum; ++ ++ g_hash_table_remove(obj->active_object_map, oid); ++ ++ if(obj->request_processing == PortableServer_USE_SERVANT_MANAGER) { ++ POA_PortableServer_ServantActivator__epv *epv; ++ POA_PortableServer_ServantActivator *sm; ++ ++ sm = (POA_PortableServer_ServantActivator *)obj->servant_manager; ++ epv = sm->vepv->PortableServer_ServantActivator_epv; ++ epv->etherealize(sm, oldobj->object_id, obj, ++ oldobj->servant, ++ CORBA_FALSE, ++ CORBA_FALSE, ++ ev); ++ } ++ ++ CORBA_free(oldobj->object_id); ++ ++ g_free(oldobj); ++ ev->_major = CORBA_NO_EXCEPTION; ++} ++ ++CORBA_Object ++PortableServer_POA_create_reference(PortableServer_POA obj, ++ CORBA_RepositoryId intf, ++ CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++PortableServer_ObjectId *PortableServer_POA_servant_to_id(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev) ++{ ++ PortableServer_ObjectId *retval, *orig; ++ PortableServer_ServantBase *serv = p_servant; ++ g_return_val_if_fail(p_servant != NULL, NULL); ++ ++ orig = ORBIT_OBJECT_KEY(serv->_private)->object->object_id; ++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ retval->_length = retval->_maximum = orig->_length; ++ retval->_buffer = CORBA_octet_allocbuf(retval->_length); ++ memcpy(retval->_buffer, orig->_buffer, retval->_length); ++ CORBA_sequence_set_release(retval, CORBA_TRUE); ++ ++ return retval; ++} ++ ++CORBA_Object ++PortableServer_POA_servant_to_reference(PortableServer_POA obj, PortableServer_Servant p_servant, CORBA_Environment *ev) ++{ ++ CORBA_Object retval; ++ PortableServer_ObjectId *orig_id; ++ PortableServer_ServantBase *servant = p_servant; ++ ORBit_ObjectKey *obj_key = ORBIT_OBJECT_KEY(servant->_private); ++ ++ int implicit = (obj->implicit_activation == PortableServer_IMPLICIT_ACTIVATION); ++ int activate_able = (obj_key->object == 0) || ++ (obj->id_uniqueness==PortableServer_MULTIPLE_ID); ++ /* ImplicitActivationPolicy */ ++ if( implicit && activate_able) { ++ orig_id = PortableServer_POA_activate_object(obj, p_servant, ev); ++ } else { ++ orig_id = obj_key->object->object_id; ++ } ++ retval = PortableServer_POA_id_to_reference(obj,orig_id,ev); ++ ++ return retval; ++} ++ ++PortableServer_Servant ++PortableServer_POA_reference_to_servant(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev) ++{ ++ GSList *cur; ++ ++ g_assert(reference); ++ ++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT ++ && obj->servant_retention != PortableServer_RETAIN) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ if(reference->servant) ++ return reference->servant; ++ ++ for(cur = reference->profile_list; cur; cur = cur->next) { ++ PortableServer_ObjectId *oid; ++ ORBit_Object_info *curprof = cur->data; ++ ORBit_POAObject *objinfo; ++ ++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(curprof->object_key), &oid); ++ CORBA_free(oid); ++ if(objinfo) ++ return objinfo->servant; ++ } ++ ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_ObjectNotActive, ++ NULL); ++ return NULL; ++} ++ ++PortableServer_ObjectId *PortableServer_POA_reference_to_id(PortableServer_POA obj, CORBA_Object reference, CORBA_Environment *ev) ++{ ++ PortableServer_ObjectId *retval; ++ ORBit_POAObject *objinfo; ++ ++ g_assert(reference); ++ g_assert(reference->active_profile); ++ ++ if(obj->request_processing != PortableServer_USE_DEFAULT_SERVANT ++ && obj->servant_retention != PortableServer_RETAIN) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ objinfo = ORBit_POA_find_oid_for_object_key(obj, &(reference->active_profile->object_key), &retval); ++ if(objinfo) { ++ CORBA_free(retval); ++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ retval->_length = retval->_maximum = objinfo->object_id->_length; ++ retval->_buffer = CORBA_octet_allocbuf(retval->_length); ++ memcpy(retval->_buffer, objinfo->object_id->_buffer, retval->_length); ++ CORBA_sequence_set_release(retval, CORBA_TRUE); ++ return retval; ++ } else if(retval) ++ return retval; ++ ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_ObjectNotActive, ++ NULL); ++ return NULL; ++} ++ ++PortableServer_Servant PortableServer_POA_id_to_servant(PortableServer_POA obj, PortableServer_ObjectId *oid, CORBA_Environment *ev) ++{ ++ ORBit_POAObject *objinfo; ++ ++ if(obj->servant_retention != PortableServer_RETAIN) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ objinfo = g_hash_table_lookup(obj->active_object_map, ++ oid); ++ ++ if(!objinfo) { ++ CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ++ ex_PortableServer_POA_WrongPolicy, ++ NULL); ++ return NULL; ++ } ++ ++ return objinfo->servant; ++} ++ ++static CORBA_Object ++my_PortableServer_POA_id_to_reference(PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ const char *type_id, ++ CORBA_Environment *ev) ++{ ++ GSList *profiles=NULL; ++ ORBit_Object_info *object_info; ++ CORBA_Object retval; ++ CORBA_ORB orb; ++ ORBit_POAObject *pobj; ++ ORBit_ObjectKey *objkey = NULL; ++ ++ orb = obj->the_POAManager->orb; ++ ++ g_assert(!oid->_buffer[oid->_length - 1]); ++ ++ pobj = g_hash_table_lookup(obj->active_object_map, oid); ++ ++ if(pobj) { ++ objkey = ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)pobj->servant)->_private); ++ type_id= objkey->class_info->class_name; ++ } ++ ++ /* Do the local connection first, so it will be attempted first by ++ the client parsing the IOR string ++ */ ++ if(orb->cnx.ipv6 || orb->cnx.usock) { ++ object_info = g_new0(ORBit_Object_info, 1); ++ ++ object_info->profile_type=IOP_TAG_ORBIT_SPECIFIC; ++ object_info->iiop_major = 1; ++ object_info->iiop_minor = 0; ++ ++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key); ++ ++#ifdef HAVE_IPV6 ++ if(orb->cnx.ipv6) { ++ object_info->tag.orbitinfo.ipv6_port = ++ ntohs(IIOP_CONNECTION(orb->cnx.ipv6)->u.ipv6.location.sin_port); ++ } ++#endif ++ if(orb->cnx.usock) { ++ object_info->tag.orbitinfo.unix_sock_path = ++ g_strdup(IIOP_CONNECTION(orb->cnx.usock)->u.usock.sun_path); ++ } ++ ORBit_set_object_key(object_info); ++ profiles=g_slist_append(profiles, object_info); ++ } ++ ++ if(orb->cnx.ipv4) { ++ object_info=g_new0(ORBit_Object_info, 1); ++ ++ object_info->profile_type = IOP_TAG_INTERNET_IOP; ++ object_info->iiop_major = 1; ++ object_info->iiop_minor = 0; ++ ORBit_POA_find_object_key_for_oid(obj, pobj, oid, &object_info->object_key); ++ ++ object_info->tag.iopinfo.host = g_strdup(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.hostname); ++ object_info->tag.iopinfo.port = ntohs(IIOP_CONNECTION(orb->cnx.ipv4)->u.ipv4.location.sin_port); ++ ++ ORBit_set_object_key(object_info); ++ profiles=g_slist_append(profiles, object_info); ++ } ++ ++ retval = ORBit_create_object_with_info(profiles, type_id, orb, ev); ++ ++ if(retval != CORBA_OBJECT_NIL ++ && ev->_major == CORBA_NO_EXCEPTION ++ && objkey && objkey->class_info && objkey->class_info->init_local_objref) { ++ /* XXX potential memleak if we get an already-valid objref */ ++ retval->vepv = g_new0(gpointer, ORBit_class_assignment_counter + 1); ++ retval->vepv_size = ORBit_class_assignment_counter + 1; ++ objkey->class_info->init_local_objref(retval, pobj->servant); ++ retval->servant = pobj->servant; ++ } else ++ retval->vepv = retval->servant = NULL; ++ ++ return retval; ++} ++ ++CORBA_Object PortableServer_POA_id_to_reference(PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_Environment *ev) ++{ ++ return my_PortableServer_POA_id_to_reference(obj, oid, NULL, ev); ++} ++ ++CORBA_Object ++PortableServer_POA_create_reference_with_id(PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_RepositoryId intf, ++ CORBA_Environment *ev) ++{ ++ return my_PortableServer_POA_id_to_reference(obj, oid, intf, ev); ++} ++ ++PortableServer_POA PortableServer_Current_get_POA(PortableServer_Current obj, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++PortableServer_ObjectId *PortableServer_Current_get_object_id(PortableServer_Current obj, CORBA_Environment *ev) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++ ++CORBA_char *PortableServer_ObjectId_to_string(PortableServer_ObjectId *id, CORBA_Environment *env) ++{ ++ return CORBA_string_dup((CORBA_char *)id->_buffer); ++} ++ ++CORBA_wchar *PortableServer_ObjectId_to_wstring(PortableServer_ObjectId *id, CORBA_Environment *env) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++PortableServer_ObjectId *PortableServer_string_to_ObjectId(CORBA_char *str, CORBA_Environment *env) ++{ ++ PortableServer_ObjectId *retval; ++ ++ retval = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); ++ ++ retval->_length = strlen(str) + 1; ++ retval->_buffer = CORBA_octet_allocbuf(retval->_length); ++ ++ memcpy(retval->_buffer, str, retval->_length); ++ ++ return retval; ++} ++ ++PortableServer_ObjectId *PortableServer_wstring_to_ObjectId(CORBA_wchar *str, CORBA_Environment *env) ++{ ++ g_assert(!"Not yet implemented"); ++ return(NULL); ++} ++ ++ ++PortableServer_POA PortableServer_ServantBase__default_POA(PortableServer_Servant servant, CORBA_Environment *ev) ++{ ++ g_return_val_if_fail(servant, NULL); ++ ++ return ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->object->poa; ++} ++ ++void PortableServer_ServantLocator_preinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie *cookie) ++{ ++ g_assert(!"Not yet implemented"); ++ return; ++} ++ ++void PortableServer_ServantLocator_postinvoke(PortableServer_ObjectId *oid, PortableServer_POA adapter, CORBA_Identifier op_name, PortableServer_ServantLocator_Cookie cookie, PortableServer_Servant servant) ++{ ++ g_assert(!"Not yet implemented"); ++ return; ++} ++ ++void PortableServer_ServantBase__init(PortableServer_Servant servant, ++ CORBA_Environment *ev) ++{ ++ PortableServer_ServantBase *serv = servant; ++ ++ if(!serv->_private) /* If not already initialized, create the place to ++ stick our info */ ++ serv->_private = g_new0(ORBit_ObjectKey, 1); ++} ++ ++void PortableServer_ServantBase__fini(PortableServer_Servant servant, ++ CORBA_Environment *ev) ++{ ++ PortableServer_ServantBase *serv = servant; ++ ++ g_free(serv->_private); ++ serv->_private = NULL; ++} ++ ++ ++/************************ ServerRequest stuff ********************/ ++ ++CORBA_Identifier CORBA_ServerRequest_operation(CORBA_ServerRequest req, CORBA_Environment *env) ++{ ++ return CORBA_string_dup(req->rbuf->message.u.request.operation); ++} ++ ++CORBA_Context ++CORBA_ServerRequest_ctx(CORBA_ServerRequest req, CORBA_Environment *env) ++{ ++ if(!req->params || req->did_ctx) { ++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER, ++ CORBA_COMPLETED_NO); ++ return NULL; ++ } ++ ++ return NULL; ++} ++ ++void ++CORBA_ServerRequest_arguments(CORBA_ServerRequest req, ++ CORBA_NVList *parameters, ++ CORBA_Environment *env) ++{ ++ int i; ++ ++ if(req->params) { ++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ req->params = parameters; ++ ++ for(i = 0; i < parameters->list->len; i++) { ++ CORBA_NamedValue *cur; ++ ++ cur = &g_array_index(parameters->list, CORBA_NamedValue, i); ++ ++ if(cur->arg_modes & CORBA_ARG_OUT) continue; ++ cur->argument._value = ORBit_demarshal_arg(req->rbuf, ++ cur->argument._type, ++ TRUE, ++ (CORBA_ORB)req->orb); ++ CORBA_any_set_release(&cur->argument, TRUE); ++ } ++} ++ ++void ++CORBA_ServerRequest_set_result(CORBA_ServerRequest req, ++ CORBA_any *value, ++ CORBA_Environment *env) ++{ ++ if(req->sbuf) { ++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection, ++ NULL, ++ req->rbuf->message.u.request.request_id, ++ CORBA_NO_EXCEPTION); ++ if(!req->sbuf) { ++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type); ++} ++ ++void ++CORBA_ServerRequest_set_exception(CORBA_ServerRequest req, ++ CORBA_exception_type major, ++ CORBA_any *value, ++ CORBA_Environment *env) ++{ ++ if(req->sbuf) { ++ CORBA_exception_set_system(env, ex_CORBA_BAD_INV_ORDER, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ req->sbuf = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(req->rbuf)->connection, ++ NULL, ++ req->rbuf->message.u.request.request_id, ++ major); ++ if(!req->sbuf) { ++ CORBA_exception_set_system(env, ex_CORBA_COMM_FAILURE, ++ CORBA_COMPLETED_NO); ++ return; ++ } ++ ++ req->did_exc = TRUE; ++ ++ /* XXX do we really need to copy the repo_id into the ++ send buffer? Or is there a way to assume that the CORBA_TypeCode ++ value->_type will be around until after we send the message? */ ++ { ++ CORBA_unsigned_long slen; ++ slen = strlen(value->_type->repo_id) + 1; ++ giop_send_buffer_append_mem_indirect_a(req->sbuf, &slen, ++ sizeof(slen)); ++ giop_send_buffer_append_mem_indirect(req->sbuf, ++ value->_type->repo_id, ++ slen); ++ } ++ ++ ORBit_marshal_arg(req->sbuf, value->_value, value->_type); ++} ++ ++void ++POA_PortableServer_ServantActivator__init(PortableServer_Servant servant, ++ CORBA_Environment * ev) ++{ ++ static const PortableServer_ClassInfo class_info = ++ {NULL, ++ "IDL:omg.org/PortableServer/ServantActivator:1.0", ++ NULL}; ++ ++ PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), ev); ++ ++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info; ++} ++ ++void ++POA_PortableServer_ServantActivator__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ServantBase__fini(servant, ev); ++} ++ ++void ++POA_PortableServer_ServantLocator__init(PortableServer_Servant servant, ++ CORBA_Environment * ev) ++{ ++ static const PortableServer_ClassInfo class_info = ++ {NULL, ++ "IDL:omg.org/PortableServer/ServantLocator:1.0", ++ NULL}; ++ ++ PortableServer_ServantBase__init(((PortableServer_ServantBase *)servant), ev); ++ ++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = (gpointer)&class_info; ++} ++ ++void ++POA_PortableServer_ServantLocator__fini(PortableServer_Servant servant, ++ CORBA_Environment * ev) ++{ ++ PortableServer_ServantBase__fini(servant, ev); ++} ++ ++/* POA-related DSI stuff */ ++static void ++dynamic_impl_skel(PortableServer_DynamicImpl *_ORBIT_servant, ++ GIOPRecvBuffer *_ORBIT_recv_buffer, ++ CORBA_Environment *ev, ++ PortableServer_DynamicImplRoutine invoke) ++{ ++ /* here the magic occurs... */ ++ struct CORBA_ServerRequest_type sr; ++ ++ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(&sr), ++ ORBIT_PSEUDO_SERVERREQUEST, ev); ++ ++ CORBA_Object_duplicate((CORBA_Object)&sr, ev); /* just to make ++ sure it doesn't die ++ elsewhere */ ++ ++ sr.rbuf = _ORBIT_recv_buffer; ++ sr.orb = GIOP_MESSAGE_BUFFER(_ORBIT_recv_buffer)->connection->orb_data; ++ ++ _ORBIT_servant->vepv->PortableServer_DynamicImpl_epv->invoke(_ORBIT_servant, ++ &sr); ++ ++ if(sr.sbuf) { ++ int i; ++ for(i = 0; i < sr.params->list->len; i++) { ++ CORBA_NamedValue *cur; ++ ++ cur = &g_array_index(sr.params->list, CORBA_NamedValue, i); ++ ++ if(cur->arg_modes & CORBA_ARG_IN) continue; ++ ++ ORBit_marshal_arg(sr.sbuf, cur->argument._value, ++ cur->argument._type); ++ } ++ ++ giop_send_buffer_write(sr.sbuf); ++ giop_send_buffer_unuse(sr.sbuf); ++ } else ++ g_warning("Yo, your DSI code is messed up! You forgot to set_result|set_exception"); ++ ++ CORBA_NVList_free(sr.params, ev); ++} ++ ++static ORBitSkeleton ++dynamic_impl_get_skel(PortableServer_DynamicImpl * servant, ++ GIOPRecvBuffer * _ORBIT_recv_buffer, ++ gpointer * impl) ++{ ++ *impl = (gpointer)servant->vepv->PortableServer_DynamicImpl_epv->invoke; ++ ++ return (ORBitSkeleton)dynamic_impl_skel; ++} ++ ++void ++PortableServer_DynamicImpl__init(PortableServer_Servant servant, ++ CORBA_Environment *ev) ++{ ++ static const PortableServer_ClassInfo class_info = ++ {(ORBitSkeleton (*)(PortableServer_ServantBase *, gpointer, gpointer *)) ++ &dynamic_impl_get_skel, "IDL:CORBA/Object:1.0", NULL}; ++ ++ PortableServer_ServantBase__init(servant, ev); ++ ++ ORBIT_OBJECT_KEY(((PortableServer_ServantBase *)servant)->_private)->class_info = ++ (PortableServer_ClassInfo *) & class_info; ++ ++} ++ ++void PortableServer_DynamicImpl__fini(PortableServer_Servant servant, ++ CORBA_Environment *ev) ++{ ++ PortableServer_ServantBase__fini(servant, ev); ++} ++ +diff -urN linux-2.4.1/net/korbit/orb/poa.h linux-2.4.1-korbit/net/korbit/orb/poa.h +--- linux-2.4.1/net/korbit/orb/poa.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/poa.h Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,337 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_POA_H_ ++#define _ORBIT_POA_H_ ++ ++#include "orbit_types.h" ++ ++extern PortableServer_ThreadPolicyValue PortableServer_ThreadPolicy__get_value( ++ PortableServer_ThreadPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_LifespanPolicyValue PortableServer_LifespanPolicy__get_value( ++ PortableServer_LifespanPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_IdUniquenessPolicyValue PortableServer_IdUniquenessPolicy__get_value( ++ PortableServer_IdUniquenessPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_IdAssignmentPolicyValue PortableServer_IdAssignmentPolicy__get_value( ++ PortableServer_IdAssignmentPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ImplicitActivationPolicyValue PortableServer_ImplicitActivationPolicy__get_value( ++ PortableServer_ImplicitActivationPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ServantRetentionPolicyValue PortableServer_ServantRetentionPolicy__get_value( ++ PortableServer_ServantRetentionPolicy obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_RequestProcessingPolicyValue PortableServer_RequestProcessingPolicy__get_value( ++ PortableServer_RequestProcessingPolicy obj, ++ CORBA_Environment *ev); ++ ++PortableServer_POAManager_State ++PortableServer_POAManager_get_state(PortableServer_POAManager obj, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POAManager_activate( ++ PortableServer_POAManager obj, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POAManager_hold_requests( ++ PortableServer_POAManager obj, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POAManager_discard_requests( ++ PortableServer_POAManager obj, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POAManager_deactivate( ++ PortableServer_POAManager obj, ++ CORBA_boolean etherealize_objects, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev); ++ ++extern CORBA_boolean PortableServer_AdapterActivator_unknown_adapter( ++ PortableServer_AdapterActivator obj, ++ PortableServer_POA parent, ++ CORBA_char *name, ++ CORBA_Environment *ev); ++ ++extern PortableServer_Servant PortableServer_ServantActivator_incarnate( ++ PortableServer_ServantActivator obj, ++ PortableServer_ObjectId *oid, ++ PortableServer_POA adapter, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_ServantActivator_etherealize( ++ PortableServer_ServantActivator obj, ++ PortableServer_ObjectId *oid, ++ PortableServer_POA adapter, ++ PortableServer_Servant serv, ++ CORBA_boolean cleanup_in_progress, ++ CORBA_boolean remaining_activations, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POA PortableServer_POA_create_POA( ++ PortableServer_POA obj, ++ CORBA_char *adapter_name, ++ PortableServer_POAManager a_POAManager, ++ CORBA_PolicyList *policies, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POA PortableServer_POA_find_POA( ++ PortableServer_POA obj, ++ CORBA_char *adapter_name, ++ CORBA_boolean activate_it, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA_destroy( ++ PortableServer_POA obj, ++ CORBA_boolean etherealize_objects, ++ CORBA_boolean wait_for_completion, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ThreadPolicy PortableServer_POA_create_thread_policy( ++ PortableServer_POA obj, ++ PortableServer_ThreadPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_LifespanPolicy PortableServer_POA_create_lifespan_policy( ++ PortableServer_POA obj, ++ PortableServer_LifespanPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_IdUniquenessPolicy PortableServer_POA_create_id_uniqueness_policy( ++ PortableServer_POA obj, ++ PortableServer_IdUniquenessPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_IdAssignmentPolicy PortableServer_POA_create_id_assignment_policy( ++ PortableServer_POA obj, ++ PortableServer_IdAssignmentPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ImplicitActivationPolicy PortableServer_POA_create_implicit_activation_policy( ++ PortableServer_POA obj, ++ PortableServer_ImplicitActivationPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ServantRetentionPolicy PortableServer_POA_create_servant_retention_policy( ++ PortableServer_POA obj, ++ PortableServer_ServantRetentionPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern PortableServer_RequestProcessingPolicy PortableServer_POA_create_request_processing_policy( ++ PortableServer_POA obj, ++ PortableServer_RequestProcessingPolicyValue value, ++ CORBA_Environment *ev); ++ ++extern CORBA_char *PortableServer_POA__get_the_name( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POA PortableServer_POA__get_the_parent( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POAManager PortableServer_POA__get_the_POAManager( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_AdapterActivator PortableServer_POA__get_the_activator( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA__set_the_activator( ++ PortableServer_POA obj, ++ PortableServer_AdapterActivator the_activator, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ServantManager PortableServer_POA_get_servant_manager( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA_set_servant_manager( ++ PortableServer_POA obj, ++ PortableServer_ServantManager imgr, ++ CORBA_Environment *ev); ++ ++extern PortableServer_Servant PortableServer_POA_get_servant( ++ PortableServer_POA obj, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA_set_servant( ++ PortableServer_POA obj, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ObjectId *PortableServer_POA_activate_object( ++ PortableServer_POA obj, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA_activate_object_with_id( ++ PortableServer_POA obj, ++ PortableServer_ObjectId *id, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_POA_deactivate_object( ++ PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object PortableServer_POA_create_reference( ++ PortableServer_POA obj, ++ CORBA_RepositoryId intf, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object PortableServer_POA_create_reference_with_id( ++ PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_RepositoryId intf, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ObjectId *PortableServer_POA_servant_to_id( ++ PortableServer_POA obj, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object PortableServer_POA_servant_to_reference( ++ PortableServer_POA obj, ++ PortableServer_Servant p_servant, ++ CORBA_Environment *ev); ++ ++extern PortableServer_Servant PortableServer_POA_reference_to_servant( ++ PortableServer_POA obj, ++ CORBA_Object reference, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ObjectId *PortableServer_POA_reference_to_id( ++ PortableServer_POA obj, ++ CORBA_Object reference, ++ CORBA_Environment *ev); ++ ++extern PortableServer_Servant PortableServer_POA_id_to_servant( ++ PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_Environment *ev); ++ ++extern CORBA_Object PortableServer_POA_id_to_reference( ++ PortableServer_POA obj, ++ PortableServer_ObjectId *oid, ++ CORBA_Environment *ev); ++ ++extern PortableServer_POA PortableServer_Current_get_POA( ++ PortableServer_Current obj, ++ CORBA_Environment *ev); ++ ++extern PortableServer_ObjectId *PortableServer_Current_get_object_id( ++ PortableServer_Current obj, ++ CORBA_Environment *ev); ++ ++extern CORBA_char *PortableServer_ObjectId_to_string( ++ PortableServer_ObjectId *id, ++ CORBA_Environment *env); ++ ++extern CORBA_wchar *PortableServer_ObjectId_to_wstring( ++ PortableServer_ObjectId *id, ++ CORBA_Environment *env); ++ ++extern PortableServer_ObjectId *PortableServer_string_to_ObjectId( ++ CORBA_char *str, ++ CORBA_Environment *env); ++ ++extern PortableServer_ObjectId *PortableServer_wstring_to_ObjectId( ++ CORBA_wchar *str, ++ CORBA_Environment *env); ++ ++extern PortableServer_POA PortableServer_ServantBase__default_POA( ++ PortableServer_Servant, ++ CORBA_Environment *); ++ ++extern void PortableServer_ServantLocator_preinvoke( ++ PortableServer_ObjectId *oid, ++ PortableServer_POA adapter, ++ CORBA_Identifier op_name, ++ PortableServer_ServantLocator_Cookie *cookie); ++ ++extern void PortableServer_ServantLocator_postinvoke( ++ PortableServer_ObjectId *oid, ++ PortableServer_POA adapter, ++ CORBA_Identifier op_name, ++ PortableServer_ServantLocator_Cookie cookie, ++ PortableServer_Servant servant); ++ ++extern void PortableServer_ServantBase__init( ++ PortableServer_Servant, ++ CORBA_Environment *); ++ ++extern void PortableServer_ServantBase__fini( ++ PortableServer_Servant, ++ CORBA_Environment *); ++ ++/* 19.27 */ ++extern CORBA_Identifier CORBA_ServerRequest_operation( ++ CORBA_ServerRequest req, ++ CORBA_Environment *env); ++ ++extern CORBA_Context CORBA_ServerRequest_ctx( ++ CORBA_ServerRequest req, ++ CORBA_Environment *env); ++ ++extern void CORBA_ServerRequest_arguments( ++ CORBA_ServerRequest req, ++ CORBA_NVList *parameters, ++ CORBA_Environment *env); ++ ++extern void CORBA_ServerRequest_set_result( ++ CORBA_ServerRequest req, ++ CORBA_any *value, ++ CORBA_Environment *env); ++ ++extern void CORBA_ServerRequest_set_exception( ++ CORBA_ServerRequest req, ++ CORBA_exception_type major, ++ CORBA_any *value, ++ CORBA_Environment *env); ++ ++extern void PortableServer_DynamicImpl__init(PortableServer_Servant, ++ CORBA_Environment *ev); ++ ++extern void PortableServer_DynamicImpl__fini(PortableServer_Servant, ++ CORBA_Environment *ev); ++ ++ ++#include "orbit_poa_type.h" ++ ++#endif /* !_ORBIT_POA_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/sequences.c linux-2.4.1-korbit/net/korbit/orb/sequences.c +--- linux-2.4.1/net/korbit/orb/sequences.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/sequences.c Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,35 @@ ++#include "orbit.h" ++#include "sequences.h" ++ ++gpointer CORBA_sequence_octet_free(gpointer mem, ++ gpointer func_data) ++{ ++ CORBA_sequence_octet *seqo = mem; ++ ++ if(seqo->_release) ++ CORBA_free(seqo->_buffer); ++ ++ return (gpointer)((guchar *)mem + sizeof(CORBA_sequence_octet)); ++} ++ ++CORBA_octet * ++CORBA_octet_allocbuf(CORBA_unsigned_long len) ++{ ++ return (CORBA_octet *)ORBit_alloc(len, NULL, NULL); ++} ++ ++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void) ++{ ++ CORBA_sequence_octet *seqo; ++ ++ seqo = ORBit_alloc(sizeof(CORBA_sequence_octet), ++ (ORBit_free_childvals)CORBA_sequence_octet_free, ++ GUINT_TO_POINTER(1)); ++ ++ seqo->_length = seqo->_maximum = 0; ++ seqo->_buffer = NULL; ++ seqo->_release = CORBA_TRUE; ++ ++ return seqo; ++} ++ +diff -urN linux-2.4.1/net/korbit/orb/sequences.h linux-2.4.1-korbit/net/korbit/orb/sequences.h +--- linux-2.4.1/net/korbit/orb/sequences.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/sequences.h Thu Feb 1 16:21:19 2001 +@@ -0,0 +1,35 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_SEQUENCES_H_ ++#define _ORBIT_SEQUENCES_H_ ++ ++/* #include "corba_sequences_type.h" */ ++#include "orbit_types.h" ++ ++CORBA_octet *CORBA_octet_allocbuf(CORBA_unsigned_long len); ++CORBA_sequence_octet *CORBA_sequence_octet__alloc(void); ++ ++#endif /* !_ORBIT_SEQUENCES_H_ */ +diff -urN linux-2.4.1/net/korbit/orb/server.c linux-2.4.1-korbit/net/korbit/orb/server.c +--- linux-2.4.1/net/korbit/orb/server.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/server.c Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,217 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* Elliot's stuff */ ++/* This is somewhat a mess, because I tried to make it easy to add ++ select() support, and as a result #ifdef's litter the land. */ ++ ++#include "orbit.h" ++#include "orbit_poa.h" ++#include "orbit_poa_type.h" ++#include <IIOP/IIOP-private.h> ++#ifdef HAVE_SYS_POLL_H ++#include <sys/poll.h> ++#endif ++#include <sys/types.h> ++#include <sys/socket.h> ++ ++/* We need: ++ a way to find out what FD's need to be selected on ++ a dummy main loop to implement the CORBA_ORB_run() routine; ++*/ ++ ++gboolean orb_server_keep_running = FALSE; ++ ++ORBit_request_validate ORBIT_request_validator = NULL; ++ ++/* function protos */ ++static PortableServer_POA ORBit_find_POA_for_request(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer); ++static PortableServer_POA ORBit_find_POA_for_locate_request(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer); ++ ++static void ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer); ++ ++void ++ORBit_custom_run_setup(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ IIOPIncomingMessageHandler = ORBit_handle_incoming_message; ++} ++ ++ ++#if __KERNEL__ ++// Modules don't do anything when they call this... ++void CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev) { ++ // This should probably free the ORB pointer, because it is a ++ // duplicated pointer from the one true orb. ++ ++} ++ ++// The ORB thread calls __CORBA_ORB_run by itself. ++#define CORBA_ORB_run __CORBA_ORB_run ++ ++#endif ++ ++void ++CORBA_ORB_run(CORBA_ORB orb, CORBA_Environment *ev) ++{ ++ ORBit_custom_run_setup(orb, ev); ++ ++ orb_server_keep_running = TRUE; ++ ++ giop_main(); ++} ++ ++static void ++ORBit_handle_incoming_request(GIOPRecvBuffer *recv_buffer) ++{ ++ CORBA_ORB orb; ++ PortableServer_POA poa; ++ GIOPConnection *connection; ++ ORBit_MessageValidationResult mvr; ++ gboolean do_unuse = TRUE; ++ ++ g_assert(recv_buffer); ++ ++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection; ++ g_return_if_fail(connection != NULL); ++ ++ orb = connection->orb_data; ++ ++ g_return_if_fail(orb != NULL); ++ ++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug, ++ "Received request %s, id %d, on %s", ++ recv_buffer->message.u.request.operation, ++ recv_buffer->message.u.request.request_id, ++ recv_buffer->message.u.request.object_key._buffer); ++ ++ if(ORBIT_request_validator) ++ mvr = ORBIT_request_validator(recv_buffer->message.u.request.request_id, ++ &recv_buffer->message.u.request.requesting_principal, ++ recv_buffer->message.u.request.operation); ++ else ++ mvr = ORBIT_MESSAGE_ALLOW; ++ ++ if(mvr == ORBIT_MESSAGE_ALLOW_ALL) ++ connection->is_auth = TRUE; ++ ++ if(mvr != ORBIT_MESSAGE_BAD) { ++ /* Find the POA for this incoming request */ ++ poa = ORBit_find_POA_for_request((PortableServer_POA)orb->root_poa, ++ recv_buffer); ++ ++ if(poa) ++ do_unuse = ORBit_POA_handle_request(recv_buffer, poa); ++ else ++ g_warning("No POA found for operation %s [%d]", ++ recv_buffer->message.u.request.operation, ++ recv_buffer->message.u.request.request_id); ++ } else { ++ g_warning("Request %s, ID %d was rejected by the authentication mechanism!", ++ recv_buffer->message.u.request.operation, ++ recv_buffer->message.u.request.request_id); ++ } ++ ++ if(do_unuse) ++ giop_recv_buffer_unuse(recv_buffer); ++} ++ ++static void ++ORBit_handle_incoming_locate_request(GIOPRecvBuffer *recv_buffer) ++{ ++ CORBA_ORB orb; ++ PortableServer_POA poa; ++ GIOPConnection *connection; ++ GIOPSendBuffer *send_buffer; ++ ++ g_assert(recv_buffer!=NULL); ++ ++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection; ++ g_return_if_fail(connection != NULL); ++ ++ orb = connection->orb_data; ++ ++ g_return_if_fail(orb != NULL); ++ ++ ORBit_Trace(TraceMod_ORB, TraceLevel_Debug, ++ "Received locate request id %d, on %s", ++ recv_buffer->message.u.locate_request.request_id, ++ recv_buffer->message.u.locate_request.object_key._buffer); ++ /* Find the POA for this incoming request */ ++ poa = ORBit_find_POA_for_locate_request((PortableServer_POA)orb->root_poa, recv_buffer); ++ ++ if(poa) { ++ /* Object found, reply with "Object Here" */ ++ send_buffer = giop_send_locate_reply_buffer_use(connection, ++ recv_buffer->message.u.locate_request.request_id, ++ GIOP_OBJECT_HERE); ++ giop_send_buffer_write(send_buffer); ++ giop_send_buffer_unuse(send_buffer); ++ } else { ++ /* Object not found, reply with "Unknown Object" */ ++ send_buffer = giop_send_locate_reply_buffer_use(connection, ++ recv_buffer->message.u.locate_request.request_id, ++ GIOP_UNKNOWN_OBJECT); ++ giop_send_buffer_write(send_buffer); ++ giop_send_buffer_unuse(send_buffer); ++ } ++ ++ giop_recv_buffer_unuse(recv_buffer); ++} ++ ++static void ++ORBit_handle_incoming_message(GIOPRecvBuffer *recv_buffer) ++{ ++ GIOPConnection *connection; ++ ++ g_assert(recv_buffer); ++ ++ connection = GIOP_MESSAGE_BUFFER(recv_buffer)->connection; ++ g_return_if_fail(connection != NULL); ++ ++ switch(GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type) { ++ case GIOP_REQUEST: ++ ORBit_handle_incoming_request(recv_buffer); ++ break; ++ case GIOP_LOCATEREQUEST: ++ ORBit_handle_incoming_locate_request(recv_buffer); ++ break; ++ case GIOP_CLOSECONNECTION: ++ /* Lame hack - need to do this in a manner that isn't ++ IIOP-specific */ ++ giop_recv_buffer_unuse(recv_buffer); ++ giop_main_handle_connection_exception(connection); ++ break; ++ case GIOP_REPLY: ++ /* the above comment probably applies here also... */ ++ giop_received_list_push(recv_buffer); ++ break; ++ default: ++ g_warning("discarding message type %d (id possibly %d)", ++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type, ++ GIOP_MESSAGE_BUFFER(recv_buffer)->message_header.message_type?recv_buffer->message.u.reply.request_id:recv_buffer->message.u.request.request_id); ++ break; ++ } ++} ++ ++static PortableServer_POA ++ORBit_find_POA_for_request(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer) ++{ ++ return ORBit_POA_find_POA_for_object_key(poa, ++ &recv_buffer->message.u.request.object_key); ++} ++ ++static PortableServer_POA ++ORBit_find_POA_for_locate_request(PortableServer_POA poa, ++ GIOPRecvBuffer *recv_buffer) ++{ ++ return ORBit_POA_find_POA_for_object_key(poa, ++ &recv_buffer->message.u.locate_request.object_key); ++} ++ ++void ++ORBit_set_request_validation_handler(ORBit_request_validate validator) ++{ ++ ORBIT_request_validator = validator; ++} +diff -urN linux-2.4.1/net/korbit/orb/typecode.c linux-2.4.1-korbit/net/korbit/orb/typecode.c +--- linux-2.4.1/net/korbit/orb/typecode.c Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/typecode.c Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,104 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter, Red Hat Software ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * Elliot Lee <sopwith@cuc.edu> ++ * ++ */ ++ ++#include "orbit.h" ++#include "orbit_typecode.h" ++ ++const struct CORBA_TypeCode_struct TC_null_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_null, "null", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_void_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_void, "void", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_short_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_short, "short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_long_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_long, "long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_longlong_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longlong, "long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_ushort_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ushort, "unsigned short", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_ulong_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulong, "unsigned long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_ulonglong_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_ulonglong, "unsigned long long", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_float_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_float, "float", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_double_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_double, "double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_longdouble_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_longdouble, "long double", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_boolean_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_boolean, "boolean", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_char_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_char, "char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_wchar_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wchar, "wide char", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_octet_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_octet, "octet", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_any_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_any, "any", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_TypeCode_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_TypeCode, "TypeCode", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_Principal_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_Principal, "Principal", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_Object_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_objref, "Object Reference", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_string_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_string, "string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_wstring_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_wstring, "wide string", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++const struct CORBA_TypeCode_struct TC_CORBA_NamedValue_struct= ++ {{{(ORBit_RootObject_Interface *)&ORBit_TypeCode_epv, CORBA_FALSE, -1}, ORBIT_PSEUDO_TYPECODE}, CORBA_tk_struct, "CORBA NamedValue", "", 0, 0, NULL, NULL, NULL, NULL, -1, 0, 0, 0}; ++ ++static const CORBA_TypeCode anon_subtypes_array7[] = ++{(CORBA_TypeCode) & TC_CORBA_string_struct}; ++ ++#if (TC_IMPL_TC_CORBA_Identifier_0 == '/') ++const struct CORBA_TypeCode_struct TC_CORBA_Identifier_struct = ++{ ++ { ++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE}, ++ CORBA_tk_alias, "Identifier", "IDL:omg.org/CORBA/Identifier:1.0", ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array7, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif ++ ++#if (TC_IMPL_TC_CORBA_RepositoryId_0 == '/') ++const struct CORBA_TypeCode_struct TC_CORBA_RepositoryId_struct = ++{ ++ { ++ {(ORBit_RootObject_Interface *) & ORBit_TypeCode_epv, TRUE, -1}, ORBIT_PSEUDO_TYPECODE}, ++ CORBA_tk_alias, "RepositoryId", "IDL:omg.org/CORBA/RepositoryId:1.0", ++ 0, 1, ++ NULL, ++ (CORBA_TypeCode *) anon_subtypes_array7, ++ NULL, ++ CORBA_OBJECT_NIL, 0, -1, 0, 0 ++}; ++#endif +diff -urN linux-2.4.1/net/korbit/orb/typecode.h linux-2.4.1-korbit/net/korbit/orb/typecode.h +--- linux-2.4.1/net/korbit/orb/typecode.h Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/orb/typecode.h Thu Feb 1 11:47:14 2001 +@@ -0,0 +1,31 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ ++ ++/* ++ * ORBit: A CORBA v2.2 ORB ++ * ++ * Copyright (C) 1998 Richard H. Porter ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Dick Porter <dick@cymru.net> ++ * ++ */ ++ ++#ifndef _ORBIT_TYPECODE_H_ ++#define _ORBIT_TYPECODE_H_ ++ ++#include "orbit_types.h" ++ ++#endif /* !_ORBIT_TYPECODE_H_ */ +diff -urN linux-2.4.1/net/korbit/sup/CVS/Entries linux-2.4.1-korbit/net/korbit/sup/CVS/Entries +--- linux-2.4.1/net/korbit/sup/CVS/Entries Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Entries Thu Feb 1 11:47:15 2001 +@@ -0,0 +1 @@ ++D +diff -urN linux-2.4.1/net/korbit/sup/CVS/Repository linux-2.4.1-korbit/net/korbit/sup/CVS/Repository +--- linux-2.4.1/net/korbit/sup/CVS/Repository Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Repository Thu Feb 1 11:47:15 2001 +@@ -0,0 +1 @@ ++/cvsroot/korbit/linux/net/korbit/sup +diff -urN linux-2.4.1/net/korbit/sup/CVS/Root linux-2.4.1-korbit/net/korbit/sup/CVS/Root +--- linux-2.4.1/net/korbit/sup/CVS/Root Thu Jan 1 03:00:00 1970 ++++ linux-2.4.1-korbit/net/korbit/sup/CVS/Root Thu Feb 1 11:47:15 2001 +@@ -0,0 +1 @@ ++vraalsen@cvs.korbit.sourceforge.net:/cvsroot/korbit diff --git a/fs/libmysqlfs.c b/fs/libmysqlfs.c new file mode 100644 index 00000000000..856692d0bd1 --- /dev/null +++ b/fs/libmysqlfs.c @@ -0,0 +1,153 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + * + * 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 "libmysqlfs.h" + +int search_and_replace(char *search, char* replace, char* string) +{ + char buff[1024]; + int found=0; + char *ptr1; + const char *ptr2=buff; + char *strptr=string; + + DBUG_ENTER("search_and_replace"); + DBUG_PRINT("enter",("search: '%s' replace:'%s' string:'%s'",search,replace,string)); + strcpy(buff,string); + while(ptr1=strstr(ptr2,search)) + { + strncpy(strptr,ptr2,ptr1-buff); + strptr+=ptr1-buff; + ptr2+=ptr1-buff+strlen(search); + strcpy(strptr,replace); + strptr+=strlen(replace); + found++; + } + DBUG_RETURN(found); +} + +int show_functions(char *b, function_type type) +{ + int i=0,j=0; + struct func_st func; + DBUG_ENTER("show_functions"); + get_dynamic(&functions_array,(gptr)&func,i); + while(func.length) { + if (func.type == type) + strcpy(&b[j++*BUFLEN],func.filename); + get_dynamic(&functions_array,(gptr)&func,++i); + } + DBUG_RETURN(j); +} + +struct func_st * check_if_function(char *name, function_type type) +{ + int pathlen; + int j,i=0, len; + static struct func_st function; + char buffer[BUFLEN]; + + DBUG_ENTER("check_if_function"); + DBUG_PRINT("enter",("name: '%s' type: '%d'", name, type)); + pathlen=strlen(name); + + /* We try to compare last element in path to function names */ + get_dynamic(&functions_array,(gptr)&function,i); + while(function.length) { + function.continuous ? + (j=!strncasecmp(function.filename, name, function.length)) + : (j=!strcasecmp(function.filename,name)); + if(j) { /* This happens when function was matched */ + DBUG_PRINT("info",("Function %s detected!",function.filename)); + break; + } + get_dynamic(&functions_array,(gptr)&function,++i); + } + + /* Copy path to buffer and trip function name (if found) from it */ + if(function.length != 0) + { + DBUG_RETURN(&function); + } else { + DBUG_RETURN(0); + } +} + +/* + * parse - splits "path" into different variables + * in way "/server/database/table/(field|key)/(value|function)". If path is shorter, + * then other fields will be NULL. If path is longer than four levels or + * shorter than one level, FS_NOTEXIST is returned. + */ +int parse(const char * path, char *server, char * database, char *table, + char* field, char* value, struct func_st **funce) +{ + char buffer[BUFLEN]; + char *p=buffer; + char *x; + int len; + + DBUG_ENTER("parse"); + DBUG_PRINT("enter",("path: '%s'", path)); + + *server=*database=*table=*field=*value='\0'; + + /* Search for first slash and drop it */ + strcpy(buffer,path); + x=strtok_r(p,"/",&p); + if(x) + { + strcpy(server,x); /* First argument is server name */ + if(*p) + strcpy(database,strtok_r(p,"/",&p)); /* Second is database */ + if(p && *p) + strcpy(table ,strtok_r(p,"/",&p)); /* Third is table name */ + if(p && *p) + strcpy(field ,strtok_r(p,"/",&p)); /* Fourth is field or key name */ + if(p && *p) + strcpy(value ,strtok_r(p,"/",&p)); /* Fifth is field/key value or function */ + } + + /* We have to find if last argument is function, + * In which case we clear it + */ + if(*value) { + *funce=check_if_function(value,VALUE_FUNCTION); + if(*funce) *value='\0'; + } else if (*field) { + *funce=check_if_function(field,FIELD_FUNCTION); + if(*funce) *field='\0'; + } else if (*table) { + *funce=check_if_function(table,TABLE_FUNCTION); + if(*funce) *table='\0'; + } else if (*database) { + *funce=check_if_function(database,DATABASE_FUNCTION); + if(*funce) *database='\0'; + } else if (*server) { + *funce=check_if_function(server,SERVER_FUNCTION); + if(*funce) *server='\0'; + } else + *funce=NULL; + + DBUG_PRINT("info",("path: '%s', server: '%s', db: '%s', table: '%s', field: '%s', value: '%s', function: '%x'", + buffer, server, database, table, field, value, funce )); + if(p && *p) /* Something is in buffer - too deep in levels */ + DBUG_RETURN(-1) + else + DBUG_RETURN(0) +} + + diff --git a/fs/libmysqlfs.h b/fs/libmysqlfs.h new file mode 100644 index 00000000000..5af78b4c6d6 --- /dev/null +++ b/fs/libmysqlfs.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + * + * 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 "CorbaFS.h" + +#include <global.h> +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" + +#define BUFLEN 1024 +#define MAXDIRS 1024 + +typedef enum { + FUNC_NONE, + FUNC_SERVER_UPTIME, + FUNC_SERVER_THREADS, + FUNC_SERVER_VERSION, + FUNC_DATABASE_CREATED, + FUNC_TABLE_COUNT, + FUNC_TABLE_CREATED, + FUNC_FIELD_LENGTH, + FUNC_KEY_AVG, + FUNC_KEY_SUM, + FUNC_KEY_MAX, + FUNC_KEY_MIN +} func_enum; + + +typedef enum { + NONE_FUNCTION, + ROOT_FUNCTION, + SERVER_FUNCTION, + DATABASE_FUNCTION, + TABLE_FUNCTION, + KEY_FUNCTION, + FIELD_FUNCTION, + VALUE_FUNCTION +} function_type; + +struct func_st { + char type_s[20]; + char filename[20]; + char function[80]; + function_type type; + int length; + my_bool continuous; +} ; + + +int parse(const char* path, + char* root, + char* database, + char* table, + char* key, + char* field, + struct func_st **func +); + +gptr db_load_functions(); +int db_function(char *b,const char *server, const char *database,const char *table,const char *field, + const char *value, const char *path, struct func_st *function); +int fix_filenames(char *buf); + +DYNAMIC_ARRAY functions_array; + + diff --git a/fs/my.cnf b/fs/my.cnf new file mode 100644 index 00000000000..e70f2c30cbf --- /dev/null +++ b/fs/my.cnf @@ -0,0 +1,5 @@ +[mysqlcorbafs] +socket=/var/lib/mysql/mysql.sock +host=127.0.0.1 +user=root +#password=xxxxxx diff --git a/fs/mysqlcorbafs.c b/fs/mysqlcorbafs.c new file mode 100644 index 00000000000..70db96f64a9 --- /dev/null +++ b/fs/mysqlcorbafs.c @@ -0,0 +1,992 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + * + * 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 + */ + + +/* + * + * fsck.mysql + */ + +#include "libmysqlfs.h" +#include "mysqlcorbafs.h" +#include <getopt.h> +#define MAXPATHLEN 256 + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> + +#include <my_sys.h> +static long inodeNum; + +extern DYNAMIC_ARRAY functions_array; +enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_KEYWORDS, + OPT_LOCKS, OPT_DROP, OPT_OPTIMIZE, OPT_DELAYED, OPT_TABLES, + OPT_CHARSETS_DIR, OPT_DEFAULT_CHARSET}; + +CHANGEABLE_VAR changeable_vars[] = { + { "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096, + 24*1024L*1024L,MALLOC_OVERHEAD,1024}, + { "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096, + 24*1024L*1024L,MALLOC_OVERHEAD,1024}, + { 0, 0, 0, 0, 0, 0, 0} +}; + +CORBA_ORB orb; +PortableServer_POA poa; +CORBA_Environment *ev; +PortableServer_ObjectId *objid; +static my_bool verbose=0,opt_compress=0,extended_insert=0, lock_tables=0, + opt_quoted=0, opt_lock=0, opt_delayed=0, ignore_errors=0; + +gptr fptr; + +static const char *load_default_groups[]= { "mysqlcorbafs","client",0 }; +static char *default_charset, *current_host, *current_user, *opt_password, + *path,*fields_terminated=0, *lines_terminated=0, *enclosed=0, + *opt_enclosed=0, *escaped=0; + +static struct option long_options[] = +{ + {"add-locks", no_argument, 0,OPT_LOCKS}, + {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR}, + {"compress", no_argument, 0, 'C'}, + {"database",required_argument, 0, 'D'}, + {"debug",optional_argument, 0, '#'}, + {"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET}, + {"delayed-insert",no_argument, 0, OPT_DELAYED}, + {"fields-terminated-by", required_argument, 0, (int) OPT_FTB}, + {"fields-enclosed-by", required_argument,0, (int) OPT_ENC}, + {"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC}, + {"fields-escaped-by", required_argument,0, (int) OPT_ESC}, + {"functions",required_argument, 0, 'f'}, + {"help", no_argument, 0,'?'}, + {"host", required_argument,0, 'h'}, + {"lines-terminated-by", required_argument, 0, (int) OPT_LTB}, + {"lock-tables", no_argument, 0, 'l'}, + {"no-data", no_argument, 0, 'd'}, + {"password", optional_argument, 0, 'p'}, +#ifdef __WIN__ + {"pipe",no_argument,0, 'W'}, +#endif + {"port", required_argument,0, 'P'}, +// {"quick", no_argument,0, 'q'}, + {"quote-names",no_argument,0, 'Q'}, + {"set-variable",required_argument,0, 'O'}, + {"socket", required_argument,0, 'S'}, +#include "sslopt-longopts.h" +#ifndef DONT_ALLOW_USER_CHANGE + {"user", required_argument,0, 'u'}, +#endif + {"verbose", no_argument,0, 'v'}, + {"version", no_argument,0, 'V'}, + {0, 0, 0, 0} +}; + + +/* +void +print_table_data(MYSQL_RES *result) +{ + String separator(256); + MYSQL_ROW cur; + MYSQL_FIELD *field; + bool *num_flag; + + num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); + if (info_flag) + { + print_field_types(result); + mysql_field_seek(result,0); + } + separator.copy("+",1); + while ((field = mysql_fetch_field(result))) + { + uint length=skip_column_names ? 0 : (uint) strlen(field->name); + if (quick) + length=max(length,field->length); + else + length=max(length,field->max_length); + if (length < 4 && !IS_NOT_NULL(field->flags)) + length=4; // Room for "NULL" + field->max_length=length+1; + separator.fill(separator.length()+length+2,'-'); + separator.append('+'); + } + tee_puts(separator.c_ptr(), PAGER); + if (!skip_column_names) + { + mysql_field_seek(result,0); + (void) tee_fputs("|", PAGER); + for (uint off=0; (field = mysql_fetch_field(result)) ; off++) + { + tee_fprintf(PAGER, " %-*s|",min(field->max_length,MAX_COLUMN_LENGTH), + field->name); + num_flag[off]= IS_NUM(field->type); + } + (void) tee_fputs("\n", PAGER); + tee_puts(separator.c_ptr(), PAGER); + } + + while ((cur = mysql_fetch_row(result))) + { + (void) tee_fputs("|", PAGER); + mysql_field_seek(result,0); + for (uint off=0 ; off < mysql_num_fields(result); off++) + { + const char *str=cur[off] ? cur[off] : "NULL"; + field = mysql_fetch_field(result); + uint length=field->max_length; + if (length > MAX_COLUMN_LENGTH) + { + tee_fputs(str,PAGER); tee_fputs(" |",PAGER); + } + else + tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|", + length, str); + } + (void) tee_fputs("\n", PAGER); + } + tee_puts(separator.c_ptr(), PAGER); + my_afree((gptr) num_flag); +} + +void +print_table_data_html(MYSQL_RES *result) +{ + MYSQL_ROW cur; + MYSQL_FIELD *field; + + mysql_field_seek(result,0); + (void) tee_fputs("<TABLE BORDER=1><TR>", PAGER); + if (!skip_column_names) + { + while((field = mysql_fetch_field(result))) + { + tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ? + (field->name[0] ? field->name : + " ") : "NULL")); + } + (void) tee_fputs("</TR>", PAGER); + } + while ((cur = mysql_fetch_row(result))) + { + (void) tee_fputs("<TR>", PAGER); + for (uint i=0; i < mysql_num_fields(result); i++) + { + ulong *lengths=mysql_fetch_lengths(result); + (void) tee_fputs("<TD>", PAGER); + safe_put_field(cur[i],lengths[i]); + (void) tee_fputs("</TD>", PAGER); + } + (void) tee_fputs("</TR>", PAGER); + } + (void) tee_fputs("</TABLE>", PAGER); +} + + +void +print_table_data_xml(MYSQL_RES *result) +{ + MYSQL_ROW cur; + MYSQL_FIELD *fields; + + mysql_field_seek(result,0); + + char *statement; + statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME)); + xmlencode(statement, (char*) glob_buffer.ptr()); + + (void) my_chomp(strend(statement)); + + tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement); + + my_free(statement,MYF(MY_ALLOW_ZERO_PTR)); + + fields = mysql_fetch_fields(result); + + while ((cur = mysql_fetch_row(result))) + { + (void) tee_fputs("\n <row>\n", PAGER); + for (uint i=0; i < mysql_num_fields(result); i++) + { + char *data; + ulong *lengths=mysql_fetch_lengths(result); + data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME)); + tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + xmlencode(data, cur[i]); + safe_put_field(data, strlen(data)); + tee_fprintf(PAGER, "</%s>\n", (fields[i].name ? + (fields[i].name[0] ? fields[i].name : + " ") : "NULL")); + my_free(data,MYF(MY_ALLOW_ZERO_PTR)); + } + (void) tee_fputs(" </row>\n", PAGER); + } + (void) tee_fputs("</resultset>\n", PAGER); +} + + +void +print_table_data_vertically(MYSQL_RES *result) +{ + MYSQL_ROW cur; + uint max_length=0; + MYSQL_FIELD *field; + + while ((field = mysql_fetch_field(result))) + { + uint length=(uint) strlen(field->name); + if (length > max_length) + max_length= length; + field->max_length=length; + } + + mysql_field_seek(result,0); + for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++) + { + mysql_field_seek(result,0); + tee_fprintf(PAGER, + "*************************** %d. row ***************************\n", row_count); + for (uint off=0; off < mysql_num_fields(result); off++) + { + field= mysql_fetch_field(result); + tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name); + tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL"); + } + } +} + + + +*/ + + + +static my_bool test_if_special_chars(const char *str) +{ + for ( ; *str ; str++) + if (!isvar(*str) && *str != '$') + return 1; + return 0; +} /* test_if_special_chars */ + +char *quote_name(char *name, char *buff) +{ + char *end; + DBUG_ENTER("quote_name"); + if (!opt_quoted && !test_if_special_chars(name)) + return name; + buff[0]=QUOTE_CHAR; + *end=strmov(buff+1,name); + end[0]=QUOTE_CHAR; + end[1]=0; + DBUG_RETURN(buff); +} /* quote_name */ + +/* + * Allow the user to specify field terminator strings like: + * "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline) + * This is done by doubleing ' and add a end -\ if needed to avoid + * syntax errors from the SQL parser. + */ + +char *field_escape(char *to,const char *from,uint length) +{ + const char *end; + uint end_backslashes=0; + DBUG_ENTER("field_escape"); + + { + *to++= *from; + if (*from == '\\') + end_backslashes^=1; /* find odd number of backslashes */ + else { + if (*from == '\'' && !end_backslashes) + *to++= *from; /* We want a duplicate of "'" for MySQL */ + end_backslashes=0; + } + } + /* Add missing backslashes if user has specified odd number of backs.*/ + if (end_backslashes) + *to++= '\\'; + DBUG_RETURN(to); +} /* field_escape */ + +void safe_exit(int error) +{ + if (!first_error) + first_error= error; + if (ignore_errors) + return; + if (sock) + mysql_close(sock); + exit(error); +} +/* safe_exit */ + + +/* + * ** DBerror -- prints mysql error message and exits the program. + */ +void DBerror(MYSQL *mysql, const char *when) +{ + DBUG_ENTER("DBerror"); + my_printf_error(0,"Got error: %d: %s %s", MYF(0), + mysql_errno(mysql), mysql_error(mysql), when); + safe_exit(EX_MYSQLERR); + DBUG_VOID_RETURN; +} /* DBerror */ + +void print_version(void) +{ + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,CORBAFS_VERSION, + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} /* print_version */ + +void usage(void) +{ + uint i; + print_version(); + puts("By Tõnu Samuel. Some code is partially from other geeks around the world"); + puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); + puts("Dumping definition and data mysql database or table"); + printf("Usage: %s [OPTIONS]\n", my_progname); + printf("\n\ + -#, --debug=... Output debug log. Often this is 'd:t:o,filename`.\n\ + --character-sets-dir=...\n\ + Directory where character sets are\n\ + -?, --help Display this help message and exit.\n\ + -c, --complete-insert Use complete insert statements.\n\ + -C, --compress Use compression in server/client protocol.\n\ + --default-character-set=...\n\ + Set the default character set\n\ + -e, --extended-insert Allows utilization of the new, much faster\n\ + INSERT syntax.\n\ + --add-locks Add locks around insert statements.\n\ + --allow-keywords Allow creation of column names that are keywords.\n\ + --delayed-insert Insert rows with INSERT DELAYED.\n\ + -f, --force Continue even if we get an sql-error.\n\ + -h, --host=... Connect to host.\n"); +puts("\ + -l, --lock-tables Lock all tables for read.\n\ + -t, --no-create-info Don't write table creation info.\n\ + -d, --no-data No row information.\n\ + -O, --set-variable var=option\n\ + give a variable a value. --help lists variables\n\ + -p, --password[=...] Password to use when connecting to server.\n\ + If password is not given it's solicited on the tty.\n"); +#ifdef __WIN__ + puts("-W, --pipe Use named pipes to connect to server"); +#endif + printf("\ + -P, --port=... Port number to use for connection.\n\ + -q, --quick Don't buffer query, dump directly to stdout.\n\ + -S, --socket=... Socket file to use for connection.\n\ + --tables Overrides option --databases (-B).\n"); +#include "sslopt-usage.h" +#ifndef DONT_ALLOW_USER_CHANGE + printf("\ + -u, --user=# User for login if not current user.\n"); +#endif + printf("\ + -v, --verbose Print info about the various stages.\n\ + -V, --version Output version information and exit.\n\ +"); + print_defaults("my",load_default_groups); + + printf("\nPossible variables for option --set-variable (-O) are:\n"); + for (i=0 ; changeable_vars[i].name ; i++) + printf("%-20s current value: %lu\n", + changeable_vars[i].name, + (ulong) *changeable_vars[i].varptr); +} /* usage */ + + + +static int get_options(int *argc,char ***argv) +{ + int c,option_index; + my_bool tty_password=0; + DBUG_ENTER("get_options"); + load_defaults("my",load_default_groups,argc,argv); + set_all_changeable_vars(changeable_vars); + while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix", + long_options, &option_index)) != EOF) + { + switch(c) { + case 'e': + extended_insert=1; + break; + case OPT_DEFAULT_CHARSET: + default_charset= optarg; + break; + case OPT_CHARSETS_DIR: + charsets_dir= optarg; + break; + + ignore_errors=1; + break; + case 'h': + my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); + current_host=my_strdup(optarg,MYF(MY_WME)); + break; +#ifndef DONT_ALLOW_USER_CHANGE + case 'u': + current_user=optarg; + break; +#endif + case 'O': + if (set_changeable_var(optarg, changeable_vars)) + { + usage(); + return(1); + } + break; + case 'p': + if (optarg) + { + char *start=optarg; + my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); + opt_password=my_strdup(optarg,MYF(MY_FAE)); + while (*optarg) *optarg++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; /* Cut length of argument */ + } else + tty_password=1; + break; + case 'P': + opt_mysql_port= (unsigned int) atoi(optarg); + break; + case 'S': + opt_mysql_unix_port= optarg; + break; + case 'W': +#ifdef __WIN__ + opt_mysql_unix_port=MYSQL_NAMEDPIPE; +#endif + break; + case 'T': + path= optarg; + break; + case '#': + DBUG_PUSH(optarg ? optarg : "d:t:o"); + break; + case 'C': + opt_compress=1; + break; + case 'l': lock_tables=1; break; + case 'Q': opt_quoted=1; break; + case 'v': verbose=1; break; + case 'V': print_version(); exit(0); + default: + fprintf(stderr,"%s: Illegal option character '%c'\n",my_progname,opterr); + /* Fall throught */ + case 'I': + case '?': + usage(); + exit(0); + case (int) OPT_FTB: + fields_terminated= optarg; + break; + case (int) OPT_LTB: + lines_terminated= optarg; + break; + case (int) OPT_ENC: + enclosed= optarg; + break; + case (int) OPT_O_ENC: + opt_enclosed= optarg; + break; + case (int) OPT_ESC: + escaped= optarg; + break; + case (int) OPT_LOCKS: + opt_lock=1; + break; + case (int) OPT_OPTIMIZE: + extended_insert=opt_lock=lock_tables=1; + break; + case (int) OPT_DELAYED: + opt_delayed=1; + break; +#include "sslopt-case.h" + } + } + if (opt_delayed) + opt_lock=0; /* Can't have lock with delayed */ + if (!path && (enclosed || opt_enclosed || escaped || lines_terminated || + fields_terminated)) + { + fprintf(stderr, "%s: You must use option --tab with --fields-...\n", my_progname); + return(1); + } + + if (enclosed && opt_enclosed) + { + fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname); + return(1); + } + if (default_charset) + { + if (set_default_charset_by_name(default_charset, MYF(MY_WME))) + exit(1); + } + (*argc)-=optind; + (*argv)+=optind; + if (tty_password) + opt_password=get_tty_password(NullS); + DBUG_RETURN(0); +} /* get_options */ + + +/*** epv structures ***/ + +static PortableServer_ServantBase__epv impl_Inode_base_epv = { + NULL, /* _private data */ + NULL, /* finalize routine */ + NULL, /* default_POA routine */ +}; +static POA_CorbaFS_Inode__epv impl_Inode_epv = { + NULL, /* _private */ + (gpointer) & impl_Inode_getStatus, + (gpointer) & impl_Inode_readpage, + (gpointer) & impl_Inode_release, + +}; +static PortableServer_ServantBase__epv impl_FileSystem_base_epv = { + NULL, /* _private data */ + NULL, /* finalize routine */ + NULL, /* default_POA routine */ +}; +static POA_CorbaFS_FileSystem__epv impl_FileSystem_epv = { + NULL, /* _private */ + (gpointer) & impl_FileSystem_getInode, + (gpointer) & impl_FileSystem_readdir, + (gpointer) & impl_FileSystem_readlink, +}; + +/*** vepv structures ***/ + +static POA_CorbaFS_Inode__vepv impl_Inode_vepv = { + &impl_Inode_base_epv, + &impl_Inode_epv, +}; +static POA_CorbaFS_FileSystem__vepv impl_FileSystem_vepv = { + &impl_FileSystem_base_epv, + &impl_FileSystem_epv, +}; + +/*** Stub implementations ***/ + +static CorbaFS_Inode +impl_Inode__create(PortableServer_POA poa, CORBA_Environment * ev) +{ + CorbaFS_Inode retval; + impl_POA_CorbaFS_Inode *newservant; + PortableServer_ObjectId *objid; + + DBUG_ENTER("impl_Inode__create"); + newservant = g_new0(impl_POA_CorbaFS_Inode, 1); + newservant->servant.vepv = &impl_Inode_vepv; + newservant->poa = poa; + POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev); + objid = PortableServer_POA_activate_object(poa, newservant, ev); + CORBA_free(objid); + retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); + + DBUG_RETURN(retval); +} + +static void +impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant, + CORBA_Environment * ev) +{ + PortableServer_ObjectId *objid; + + DBUG_ENTER("impl_Inode__destroy"); + objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); + PortableServer_POA_deactivate_object(servant->poa, objid, ev); + CORBA_free(objid); + + POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev); + g_free(servant); + DBUG_VOID_RETURN; +} + +static void +impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant, + CORBA_unsigned_short * mode, + CORBA_unsigned_long * uid, + CORBA_unsigned_long * gid, + CORBA_unsigned_long * size, + CORBA_unsigned_long * inodeNum, + CORBA_unsigned_short * numLinks, + CORBA_long * atime, + CORBA_long * mtime, + CORBA_long * ctime, CORBA_Environment * ev) +{ + struct stat buf; + char + server[BUFLEN], + database[BUFLEN], + table[BUFLEN], + key[BUFLEN], + field[BUFLEN], + value[BUFLEN]; + + struct func_st *func; + + DBUG_ENTER("impl_Inode_getStatus"); + DBUG_PRINT("enter",("path: '%s', mode: '%o', uid: '%d', gid: '%d', size: '%d', + inodeNum: '%d', numLinks: '%d', atime: '%d',mtime: '%d', ctime: '%d'", + servant->path, mode, uid, gid, size, inodeNum, numLinks, atime, mtime, ctime)); + DBUG_PRINT("info",("func: %x",&func)); + if(parse(servant->path, server, database, table, field, value, &func)>0) + { + DBUG_PRINT("info",("ENOENT")); + *mode=0; + } else if (func != NULL){ + DBUG_PRINT("info",("func: %x",&func)); + DBUG_PRINT("info",("Argument is function at %x, returning S_IFREG",func)); + *mode = S_IFREG; // File + } else if (*field){ + DBUG_PRINT("info",("Argument is file, returning S_IFREG")); + *mode = S_IFREG; // File + } else { + DBUG_PRINT("info",("Argument is directory, returning S_IFDIR")); + *mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH ; // Dir + } + + *mode |= S_IRUSR | S_IRGRP | S_IROTH; + *uid = 0; + *gid = 0; + *size = 4096; + *inodeNum = servant->inodeNum; + *numLinks = 1; + *atime = 3; + *mtime = 2; + *ctime = 1; + +// lstat(servant->path, &buf); +// *mode = buf.st_mode; +/* *uid = buf.st_uid; + *gid = buf.st_gid; + *size = buf.st_size; + *inodeNum = buf.st_ino; + *numLinks = buf.st_nlink; + *atime = buf.st_atime; + *mtime = buf.st_mtime; + *ctime = buf.st_ctime;*/ + DBUG_VOID_RETURN; +} + +static void +impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant, + CorbaFS_Buffer ** buffer, + CORBA_long size, + CORBA_long offset, CORBA_Environment * ev) +{ + int type; + int fd = -1, c = 0; + int res; + char + server[BUFLEN], + database[BUFLEN], + table[BUFLEN], + key[BUFLEN], + field[BUFLEN], + value[BUFLEN]; + struct func_st *func; + + DBUG_ENTER("impl_Inode_readpage"); + DBUG_PRINT("enter",("path: '%s'", servant->path)); + *buffer = CorbaFS_Buffer__alloc(); + (*buffer)->_maximum = size; + (*buffer)->_buffer = CORBA_octet_allocbuf(size); + printf("requested to read %d bytes\n",size); + memset((*buffer)->_buffer, size, 0); + type = parse(servant->path, server, database, table, field, value, &func); + if (func != NULL) + res=db_function((*buffer)->_buffer, server, database, table, field, value, servant->path, func); + else + res=db_show_field((*buffer)->_buffer, database, table, field, path, value); + if(res>0) + (*buffer)->_length = strlen((*buffer)->_buffer); + else + (*buffer)->_length = 0; +/* + fd = open(servant->path, O_RDONLY); + printf("Inode_readpage : fd = %d\n", fd); + lseek(fd, offset, SEEK_SET); + c = read(fd, (*buffer)->_buffer, size); + printf("Inode_readpage : read %d bytes\n", c); + (*buffer)->_length = c; + close(fd); +*/ + DBUG_VOID_RETURN; +} + +static void +impl_Inode_release(impl_POA_CorbaFS_Inode * servant, + CORBA_Environment * ev) +{ + DBUG_ENTER("impl_Inode_readpage"); + DBUG_PRINT("enter",("path: '%s'", servant->path)); + DBUG_VOID_RETURN; +} + +/* + * This function is called when we get mounted + */ +CorbaFS_FileSystem +impl_FileSystem__create(PortableServer_POA poa, + CORBA_Environment * ev) +{ + CorbaFS_FileSystem retval; + impl_POA_CorbaFS_FileSystem *newservant; + PortableServer_ObjectId *objid; + + DBUG_ENTER("impl_FileSystem__create"); + newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1); + newservant->servant.vepv = &impl_FileSystem_vepv; + newservant->poa = poa; + POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev); + objid = PortableServer_POA_activate_object(poa, newservant, ev); + CORBA_free(objid); + retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); + + DBUG_RETURN(retval); +} + +/* + * This function is called when we get unmounted + */ +static void +impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant, + CORBA_Environment * ev) +{ + PortableServer_ObjectId *objid; + DBUG_ENTER("impl_FileSystem__destroy"); + + objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev); + PortableServer_POA_deactivate_object(servant->poa, objid, ev); + CORBA_free(objid); + + POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev); + g_free(servant); + DBUG_VOID_RETURN; +} + +static CorbaFS_Inode +impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * path, CORBA_Environment * ev) +{ + CorbaFS_Inode retval; + impl_POA_CorbaFS_Inode *inode; + char + database[BUFLEN], + table[BUFLEN], + key[BUFLEN], + field[BUFLEN]; + char buffer[MAXDIRS][BUFLEN]; + int c; + + DBUG_ENTER("impl_FileSystem_getInode"); + DBUG_PRINT("enter",("path: '%s'", path)); + + //FIXME: We should verify the existense of file/dir here + // + retval = impl_Inode__create(servant->poa, ev); + inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev ); + inode->path = CORBA_string_dup(path); + //FIXME: inodeNum Generation goes here + // + inode->inodeNum= inodeNum++; +#if 0 + inode->mode = 0040777; /* world-readable directory */ + inode->uid = 0; + inode->gid = 0; + inode->size = 4096; + inode->inodeNum = inodeNum++; + inode->numLinks = 1; + inode->atime = 0; + inode->mtime = 100; + inode->ctime = 10000; +#endif + DBUG_RETURN(retval); +} + + +static CorbaFS_DirEntSeq * +impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * path, CORBA_Environment * ev) +{ + CorbaFS_DirEntSeq *retval; + CorbaFS_dirent *dirent; + + struct func_st *func; + int c, c2,i; + char + server[BUFLEN], + table[BUFLEN], + field[BUFLEN], + value[BUFLEN], + buffer[MAXDIRS][BUFLEN], + buffer2[MAXDIRS][BUFLEN], + database[BUFLEN]; + + DBUG_ENTER("impl_FileSystem_readdir"); + DBUG_PRINT("enter",("path: '%s'", path)); + retval = CorbaFS_DirEntSeq__alloc(); + retval->_maximum = 0; + retval->_length = 0; + + parse(path, server, database, table, field, value, &func); + if (func != NULL) { + c2 = db_function((char *)buffer, server, database, table, field, value, path, func); + } else if(!*server) { + c2 = db_show_servers(buffer2,MAXDIRS); + c = show_functions((char *)buffer, ROOT_FUNCTION); + } else if(!*database) { + c2 = db_show_databases(buffer2,MAXDIRS); + c = show_functions((char *)buffer, SERVER_FUNCTION); + } else if(!*table){ + c2 = db_show_tables(buffer2, database); + c = show_functions((char *)buffer, DATABASE_FUNCTION); + } else if(!*field){ + c2 = db_show_primary_keys(buffer2, database,table); + if(c2>=0) { + c = show_functions((char *)buffer, TABLE_FUNCTION); + } + } else { + c2 = db_show_fields(buffer2, database, table, field); + c = show_functions((char *)buffer, FIELD_FUNCTION); + c = show_functions((char *)buffer, KEY_FUNCTION); + } + if(c2 < 0) + c=c2=0; // Error occured in database routines + + /* Allocate space to hold all found entries plus "." and ".." */ + retval->_maximum = c + c2 + 2; + retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(retval->_maximum) ; + dirent = retval->_buffer; + + i = 0; + while (i < c) { + long inode = 123L; + dirent[i].inode = inode; + dirent[i].name = CORBA_string_dup(buffer[i]); + i++; + } + i = 0; + while (i < c2) { + long inode = 123L; + dirent[c+i].inode = inode; + dirent[c+i].name = CORBA_string_dup(buffer2[i]); + i++; + } + dirent[c+i].inode = 123L; + dirent[c+i].name = CORBA_string_dup("."); + i++; + dirent[c+i].inode = 123L; + dirent[c+i].name = CORBA_string_dup(".."); + + retval->_length = retval->_maximum; + DBUG_RETURN(retval); +} + +static CORBA_char * +impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * filename, + CORBA_Environment * ev) +{ + CORBA_char *retval = CORBA_OBJECT_NIL; + char tmp[MAXPATHLEN + 1]; + int len; + + DBUG_ENTER("impl_FileSystem_readlink"); + DBUG_PRINT("enter",("path: '%s'", filename)); + +/* len = readlink(filename, tmp, MAXPATHLEN); + if (len != -1) + { + tmp[len] = '\0'; + retval = CORBA_string_dup(tmp); + } + + printf("%s\n", retval); + */ + DBUG_RETURN(retval); +} + +int fix_filenames(char *buf) +{ + int i; + for(i=0; i<strlen(buf);i++) + if(buf[i]=='/') + buf[i]='_'; +} + +int main(int argc, char *argv[]) { + CorbaFS_FileSystem fs; + impl_POA_CorbaFS_FileSystem *fs_impl; + FILE *f; + PortableServer_POAManager pm; + + DBUG_ENTER("main"); + DBUG_PROCESS(argv[0]); + ev = g_new0(CORBA_Environment,1); + CORBA_exception_init(ev); + orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev); + MY_INIT(argv[0]); + + /* + ** Check out the args + */ + if (get_options(&argc, &argv)) + { + my_end(0); + exit(EX_USAGE); + } + if (db_connect(current_host, current_user, opt_password)) + exit(EX_MYSQLERR); + fptr = db_load_functions(); + db_load_formats(); + poa = (PortableServer_POA) + CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev); + fs = impl_FileSystem__create(poa, ev); + + pm = PortableServer_POA__get_the_POAManager(poa, ev); + PortableServer_POAManager_activate(pm, ev); + + fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev ); + objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev ); + printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev)); + f=fopen("/tmp/mysqlcorbafs.ior","w"); + fputs(CORBA_ORB_object_to_string(orb, fs, ev),f); + fclose(f); + CORBA_ORB_run(orb, ev); + db_disconnect(current_host); + + return 0; +} + diff --git a/fs/mysqlcorbafs.h b/fs/mysqlcorbafs.h new file mode 100644 index 00000000000..4fd76598d7f --- /dev/null +++ b/fs/mysqlcorbafs.h @@ -0,0 +1,159 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + * + * 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 "CorbaFS.h" + +#include <global.h> +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" + +#define QUOTE_CHAR '`' +/* Exit codes */ + +#define EX_USAGE 1 +#define EX_MYSQLERR 2 +#define EX_CONSCHECK 3 +#define EX_EOM 4 + +#define CORBAFS_VERSION "0.01" + +typedef struct +{ + POA_CorbaFS_Inode servant; + PortableServer_POA poa; + + CORBA_char *path; + CORBA_unsigned_long inodeNum; +#if 0 + CORBA_unsigned_short mode; + CORBA_unsigned_long uid; + CORBA_unsigned_long gid; + CORBA_unsigned_long size; + CORBA_unsigned_short numLinks; + CORBA_long atime; + CORBA_long mtime; + CORBA_long ctime; +#endif +} +impl_POA_CorbaFS_Inode; + +typedef struct +{ + POA_CorbaFS_FileSystem servant; + PortableServer_POA poa; + +} +impl_POA_CorbaFS_FileSystem; + +/*** Implementation stub prototypes ***/ +CorbaFS_FileSystem +impl_FileSystem__create(PortableServer_POA poa, CORBA_Environment * ev); + +static void +impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant, + CORBA_Environment * ev); +static void +impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant, + CORBA_unsigned_short * mode, + CORBA_unsigned_long * uid, + CORBA_unsigned_long * gid, + CORBA_unsigned_long * size, + CORBA_unsigned_long * inodeNum, + CORBA_unsigned_short * numLinks, + CORBA_long * atime, + CORBA_long * mtime, + CORBA_long * ctime, CORBA_Environment * ev); + +static void +impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant, + CorbaFS_Buffer ** buffer, + CORBA_long size, + CORBA_long offset, CORBA_Environment * ev); + +static void +impl_Inode_release(impl_POA_CorbaFS_Inode * servant, + CORBA_Environment * ev); + +static void impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * + servant, CORBA_Environment * ev); + +static CorbaFS_Inode +impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * path, CORBA_Environment * ev); + +static CorbaFS_DirEntSeq * +impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * path, + CORBA_Environment * ev); + +static CORBA_char * +impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant, + CORBA_char * filename, + CORBA_Environment * ev); + +static my_bool verbose,opt_compress; +static uint opt_mysql_port=0; +static my_string opt_mysql_unix_port=0; +static int first_error=0; +static MYSQL connection, *sock=0; + +extern uint opt_mysql_port; +extern my_string opt_mysql_unix_port,host,user,password; + + + +static struct format { + char *tablestart; + + char *headerrowstart; + char *headercellstart; + char *headercellseparator; + char *headercellend; + char *headerrowend; + int headerformat; /* 0 - simple, 1 - left padded, 2 - right padded */ + + char *contentrowstart; + char *contentcellstart; + char *contentcellseparator; + char *contentcellend; + char *contentrowend; + int contentformat; + + char *footerrowstart; + char *footercellstart; + char *footercellseparator; + char *footercellend; + char *footerrowend; + int footerformat; + + char *tableend; + + char *leftuppercorner; + char *rightuppercorner; + char *leftdowncorner; + char *rightdowncorner; + char *leftcross; + char *rightcross; + char *topcross; + char *middlecross; + char *bottomcross; + + +} Human, HTML, CSF, XML; + + diff --git a/fs/mysqlcorbafs_test.c b/fs/mysqlcorbafs_test.c new file mode 100644 index 00000000000..81b76702303 --- /dev/null +++ b/fs/mysqlcorbafs_test.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <stdlib.h> +#include <orb/orbit.h> + +#include "CorbaFS.h" + +CorbaFS_FileSystem fs; + +int +main (int argc, char *argv[]) +{ + CORBA_Environment ev; + CORBA_ORB orb; + CorbaFS_Inode inode; + CorbaFS_Buffer *buffer; + CorbaFS_DirEntSeq *dirents; + CorbaFS_dirent *dirent; + + CORBA_unsigned_short mode; + CORBA_unsigned_long uid; + CORBA_unsigned_long gid; + CORBA_unsigned_long size; + CORBA_unsigned_long inodeNum; + CORBA_unsigned_short numLinks; + CORBA_long atime; + CORBA_long mtime; + CORBA_long ctime; + + int i; + + int niters = 10; + + CORBA_exception_init(&ev); + orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); + + if(argc < 2) + { + printf("Need a binding ID thing as argv[1]\n"); + return 1; + } + + + fs = CORBA_ORB_string_to_object(orb, argv[1], &ev); + if (!fs) { + printf("Cannot bind to %s\n", argv[1]); + return 1; + } + + if (argc >= 3) + inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev); + else + inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev); + + if (!inode) + { + printf("Cannot get inode\n"); + } + + CorbaFS_Inode_getStatus(inode, + &mode, + &uid, + &gid, + &size, + &inodeNum, + &numLinks, + &atime, + &mtime, + &ctime, + &ev); + + printf("inode = %x\n", inode); + CorbaFS_Inode_readpage(inode, &buffer, 100000, 100, &ev); + printf("readpage got %d bytes\n", buffer->_length); + printf("readpage returned : %s\n", buffer->_buffer); + + if (argc >= 3) + dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev); + else + dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev); + + dirent = dirents->_buffer; + for (i = 0; i < dirents->_length; i++) + { + printf("%d = %s\n", dirent->inode, dirent->name); + dirent++; + } + + CORBA_Object_release(fs, &ev); + CORBA_Object_release((CORBA_Object)orb, &ev); + + return 0; +} diff --git a/fs/mysqlfsck b/fs/mysqlfsck new file mode 100755 index 00000000000..7b4e049b1e3 --- /dev/null +++ b/fs/mysqlfsck @@ -0,0 +1,11 @@ +#!/bin/sh + +mountpoint=$* + +if [#($mountpoint) -eq "0"]; +then + exit; +fi + + + diff --git a/heap/hp_clear.c b/heap/hp_clear.c index 702c2e09d29..dcab35acd4e 100644 --- a/heap/hp_clear.c +++ b/heap/hp_clear.c @@ -44,7 +44,7 @@ void _hp_clear(HP_SHARE *info) block->levels=0; block->last_allocated=0; } - info->records=info->deleted=info->data_length=info->index_length=0;; + info->records=info->deleted=info->data_length=info->index_length=0; info->blength=1; info->changed=0; info->del_link=0; diff --git a/heap/hp_close.c b/heap/hp_close.c index 583602e98cb..267a068350b 100644 --- a/heap/hp_close.c +++ b/heap/hp_close.c @@ -19,7 +19,7 @@ #include "heapdef.h" /* Close a database open by hp_open() */ - /* Data is not deallocated */ + /* Data is normally not deallocated */ int heap_close(HP_INFO *info) { @@ -43,8 +43,9 @@ int _hp_close(register HP_INFO *info) } #endif info->s->changed=0; - info->s->open_count--; heap_open_list=list_delete(heap_open_list,&info->open_list); + if (!--info->s->open_count && info->s->delete_on_close) + _hp_free(info->s); /* Table was deleted */ my_free((gptr) info,MYF(0)); DBUG_RETURN(error); } diff --git a/heap/hp_create.c b/heap/hp_create.c index 01c5f43adfd..da91e412180 100644 --- a/heap/hp_create.c +++ b/heap/hp_create.c @@ -21,33 +21,49 @@ #include "heapdef.h" + int heap_create(const char *name) { + reg1 HP_SHARE *share; DBUG_ENTER("heap_create"); - (void) heap_delete_all(name); + pthread_mutex_lock(&THR_LOCK_heap); + if ((share=_hp_find_named_heap(name))) + { + if (share->open_count == 0) + _hp_free(share); + } + else + { + my_errno=ENOENT; + } + pthread_mutex_unlock(&THR_LOCK_heap); DBUG_RETURN(0); } -int heap_delete_all(const char *name) +int heap_delete_table(const char *name) { - reg1 HP_SHARE *info; - int found; - DBUG_ENTER("heap_delete_all"); + int result; + reg1 HP_SHARE *share; + DBUG_ENTER("heap_delete_table"); + pthread_mutex_lock(&THR_LOCK_heap); - if ((info=_hp_find_named_heap(name))) + if ((share=_hp_find_named_heap(name))) { - if (info->open_count == 0) - _hp_free(info); - found=0; + if (share->open_count == 0) + _hp_free(share); + else + share->delete_on_close=1; + result=0; } else { - found=my_errno=ENOENT; + result=my_errno=ENOENT; } pthread_mutex_unlock(&THR_LOCK_heap); - DBUG_RETURN(found); + DBUG_RETURN(result); } + void _hp_free(HP_SHARE *share) { heap_share_list=list_delete(heap_share_list,&share->open_list); diff --git a/heap/hp_delete.c b/heap/hp_delete.c index a6e77fe5f27..921b6cf36e6 100644 --- a/heap/hp_delete.c +++ b/heap/hp_delete.c @@ -50,7 +50,8 @@ int heap_delete(HP_INFO *info, const byte *record) info->current_hash_ptr=0; DBUG_RETURN(0); err: - if( ++(share->records) == share->blength) share->blength+= share->blength; + if (++(share->records) == share->blength) + share->blength+= share->blength; DBUG_RETURN(my_errno); } @@ -66,7 +67,8 @@ int _hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, DBUG_ENTER("_hp_delete_key"); blength=share->blength; - if (share->records+1 == blength) blength+= blength; + if (share->records+1 == blength) + blength+= blength; lastpos=hp_find_hash(&keyinfo->block,share->records); last_ptr=0; diff --git a/heap/hp_test2.c b/heap/hp_test2.c index a76aa19e082..12bd61474da 100644 --- a/heap/hp_test2.c +++ b/heap/hp_test2.c @@ -572,7 +572,7 @@ end: heap_clear(file); if (heap_close(file) || (file2 && heap_close(file2))) goto err; - heap_delete_all(filename2); + heap_delete_table(filename2); heap_panic(HA_PANIC_CLOSE); my_end(MY_GIVE_INFO); return(0); diff --git a/include/errmsg.h b/include/errmsg.h index 8087c526937..ecc9761a391 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -57,3 +57,11 @@ extern const char *client_errors[]; /* Error messages */ #define CR_NAMEDPIPESETSTATE_ERROR 2018 #define CR_CANT_READ_CHARSET 2019 #define CR_NET_PACKET_TOO_LARGE 2020 +#define CR_EMBEDDED_CONNECTION 2021 +#define CR_PROBE_SLAVE_STATUS 2022 +#define CR_PROBE_SLAVE_HOSTS 2023 +#define CR_PROBE_SLAVE_CONNECT 2024 +#define CR_PROBE_MASTER_CONNECT 2025 + + + diff --git a/include/ft_global.h b/include/ft_global.h index 3937bd87c7f..415c0884989 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -27,6 +27,7 @@ extern "C" { #endif #define FT_QUERY_MAXLEN 1024 +#define HA_FT_MAXLEN 254 typedef struct ft_doc_rec { my_off_t dpos; @@ -42,14 +43,19 @@ typedef struct st_ft_doclist { extern const char *ft_precompiled_stopwords[]; +extern uint ft_min_word_len; +extern uint ft_max_word_len; +extern uint ft_max_word_len_for_sort; + int ft_init_stopwords(const char **); void ft_free_stopwords(void); FT_DOCLIST * ft_init_search(void *, uint, byte *, uint, my_bool); int ft_read_next(FT_DOCLIST *, char *); -#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0)) -#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight) -#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1) +#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0)) +#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight) +#define ft_get_docid(handler) ((handler)->doc[(handler)->curdoc].dpos) +#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1) #ifdef __cplusplus } diff --git a/include/global.h b/include/global.h index c7d6952f1c6..7cd79b3e078 100644 --- a/include/global.h +++ b/include/global.h @@ -189,7 +189,13 @@ # endif #endif /* TIME_WITH_SYS_TIME */ #ifdef HAVE_UNISTD_H +#ifdef HAVE_OPENSSL +#define crypt dummy +#endif #include <unistd.h> +#ifdef HAVE_OPENSSL +#undef crypt +#endif #endif #if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) #undef HAVE_ALLOCA @@ -351,6 +357,7 @@ typedef int pshort; /* Mixed prototypes can't take short int */ typedef double pfloat; /* Mixed prototypes can't take float */ #endif typedef int (*qsort_cmp)(const void *,const void *); +typedef int (*qsort_cmp2)(void*, const void *,const void *); #ifdef HAVE_mit_thread #define qsort_t void #undef QSORT_TYPE_IS_VOID @@ -808,9 +815,9 @@ typedef union { *((uchar*) (T))= (uchar)(def_temp); \ *((uchar*) (T+1))=(uchar)((def_temp >> 8)); } #define int3store(T,A) { /*lint -save -e734 */\ - *((T))=(char) ((A));\ - *((T)+1)=(char) (((A) >> 8));\ - *((T)+2)=(char) (((A) >> 16)); \ + *((uchar*)(T))=(uchar) ((A));\ + *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ + *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ /*lint -restore */} #define int4store(T,A) { *(T)=(char) ((A));\ *((T)+1)=(char) (((A) >> 8));\ diff --git a/include/heap.h b/include/heap.h index 14698810297..813df2a7ddd 100644 --- a/include/heap.h +++ b/include/heap.h @@ -109,6 +109,7 @@ typedef struct st_heap_share THR_LOCK lock; pthread_mutex_t intern_lock; /* Locking for use with _locking */ #endif + my_bool delete_on_close; LIST open_list; } HP_SHARE; @@ -144,7 +145,7 @@ extern int heap_scan(register HP_INFO *info, byte *record); extern int heap_delete(HP_INFO *info,const byte *buff); extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag); extern int heap_create(const char *name); -extern int heap_delete_all(const char *name); +extern int heap_delete_table(const char *name); extern int heap_extra(HP_INFO *info,enum ha_extra_function function); extern int heap_rename(const char *old_name,const char *new_name); extern int heap_panic(enum ha_panic_function flag); diff --git a/include/my_base.h b/include/my_base.h index bb2e4128195..e677f448c57 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -91,7 +91,10 @@ enum ha_extra_function { HA_EXTRA_RESET_STATE, /* Reset positions */ HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/ HA_EXTRA_NO_IGNORE_DUP_KEY, - HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE /* Cursor will not be used for update */ + HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */ + HA_EXTRA_BULK_INSERT_BEGIN, + HA_EXTRA_BULK_INSERT_END, + HA_EXTRA_PREPARE_FOR_DELETE }; /* The following is parameter to ha_panic() */ diff --git a/include/my_pthread.h b/include/my_pthread.h index cd72bcced83..577d3dea3b2 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -623,5 +623,4 @@ extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const)); #ifdef __cplusplus } #endif - #endif /* _my_ptread_h */ diff --git a/include/my_sys.h b/include/my_sys.h index 5b45f6a91e5..b70d123a66a 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -110,7 +110,8 @@ extern int NEAR my_errno; /* Last error in mysys */ /* root_alloc flags */ #define MY_KEEP_PREALLOC 1 - +#define MY_MARK_BLOCKS_FREE 2 /* move used to free list and reuse them */ + /* defines when allocating data */ #ifdef SAFEMALLOC @@ -246,7 +247,8 @@ typedef struct st_record_cache /* Used when cacheing records */ } RECORD_CACHE; enum file_type { UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, - STREAM_BY_FOPEN, STREAM_BY_FDOPEN, FILE_BY_MKSTEMP }; + STREAM_BY_FOPEN, STREAM_BY_FDOPEN, FILE_BY_MKSTEMP, + FILE_BY_DUP }; extern struct my_file_info { @@ -270,12 +272,19 @@ typedef struct st_dynamic_string { uint length,max_length,alloc_increment; } DYNAMIC_STRING; +struct st_io_cache; +typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*); typedef struct st_io_cache /* Used when cacheing files */ { my_off_t pos_in_file,end_of_file; byte *rc_pos,*rc_end,*buffer,*rc_request_pos; int (*read_function)(struct st_io_cache *,byte *,uint); + /* callbacks when the actual read I/O happens */ + IO_CACHE_CALLBACK pre_read; + IO_CACHE_CALLBACK post_read; + IO_CACHE_CALLBACK pre_close; + void* arg; /* for use by pre/post_read */ char *file_name; /* if used with 'open_cached_file' */ char *dir,*prefix; File file; @@ -380,6 +389,7 @@ extern File my_register_filename(File fd, const char *FileName, extern File my_create(const char *FileName,int CreateFlags, int AccsesFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); +extern File my_dup(File file, myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); extern int my_readlink(char *to, const char *filename, myf MyFlags); extern int my_realpath(char *to, const char *filename, myf MyFlags); @@ -581,6 +591,7 @@ extern void my_free_lock(byte *ptr,myf flags); void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size); gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); void free_root(MEM_ROOT *root, myf MyFLAGS); +void set_prealloc_root(MEM_ROOT *root, char *ptr); char *strdup_root(MEM_ROOT *root,const char *str); char *memdup_root(MEM_ROOT *root,const char *str,uint len); void load_defaults(const char *conf_file, const char **groups, diff --git a/include/my_tree.h b/include/my_tree.h index 0a227ea3944..d3adbe17e6f 100644 --- a/include/my_tree.h +++ b/include/my_tree.h @@ -32,6 +32,9 @@ typedef enum { left_root_right, right_root_left } TREE_WALK; typedef uint32 element_count; typedef int (*tree_walk_action)(void *,element_count,void *); +typedef enum { free_init, free_free, free_end } TREE_FREE; +typedef void (*tree_element_free)(void*, TREE_FREE, void *); + #ifdef MSDOS typedef struct st_tree_element { struct st_tree_element *left,*right; @@ -49,18 +52,22 @@ typedef struct st_tree_element { typedef struct st_tree { TREE_ELEMENT *root,null_element; TREE_ELEMENT **parents[MAX_TREE_HIGHT]; - uint offset_to_key,elements_in_tree,size_of_element; - qsort_cmp compare; + uint offset_to_key,elements_in_tree,size_of_element,memory_limit,allocated; + qsort_cmp2 compare; + void* custom_arg; MEM_ROOT mem_root; my_bool with_delete; - void (*free)(void *); + tree_element_free free; } TREE; - /* Functions on hole tree */ -void init_tree(TREE *tree,uint default_alloc_size, int element_size, - qsort_cmp compare, my_bool with_delete, - void (*free_element)(void*)); + /* Functions on whole tree */ +void init_tree(TREE *tree, uint default_alloc_size, uint memory_limit, + int size, qsort_cmp2 compare, my_bool with_delete, + tree_element_free free_element, void *custom_arg); void delete_tree(TREE*); +void reset_tree(TREE*); + /* similar to delete tree, except we do not my_free() blocks in mem_root + */ #define is_tree_inited(tree) ((tree)->root != 0) /* Functions on leafs */ diff --git a/include/myisam.h b/include/myisam.h index 8d25e17e589..1752f9336a5 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library 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 Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -68,6 +68,7 @@ typedef struct st_mi_isaminfo /* Struct from h_info */ ulong mean_reclength; /* Mean recordlength (if packed) */ ulonglong auto_increment; ulonglong key_map; /* Which keys are used */ + char *data_file_name, *index_file_name; uint keys; /* Number of keys in use */ uint options; /* HA_OPTION_... used */ int errkey, /* With key was dupplicated on err */ @@ -86,6 +87,7 @@ typedef struct st_mi_isaminfo /* Struct from h_info */ typedef struct st_mi_create_info { + char *index_file_name, *data_file_name; /* If using symlinks */ ha_rows max_rows; ha_rows reloc_rows; ulonglong auto_increment; @@ -187,9 +189,10 @@ typedef struct st_columndef /* column information */ extern my_string myisam_log_filename; /* Name of logfile */ extern uint myisam_block_size; -extern my_bool myisam_flush,myisam_delay_key_write; +extern my_bool myisam_flush,myisam_delay_key_write,myisam_single_user; extern my_bool myisam_concurrent_insert; extern my_off_t myisam_max_temp_length,myisam_max_extra_temp_length; +extern uint myisam_bulk_insert_tree_size; /* Prototypes for myisam-functions */ @@ -219,7 +222,7 @@ extern my_off_t mi_position(struct st_myisam_info *file); extern int mi_status(struct st_myisam_info *info, MI_ISAMINFO *x, uint flag); extern int mi_lock_database(struct st_myisam_info *file,int lock_type); extern int mi_create(const char *name,uint keys,MI_KEYDEF *keydef, - uint columns, MI_COLUMNDEF *columndef, + uint columns, MI_COLUMNDEF *columndef, uint uniques, MI_UNIQUEDEF *uniquedef, MI_CREATE_INFO *create_info, uint flags); extern int mi_delete_table(const char *name); @@ -295,17 +298,17 @@ typedef struct st_sort_info { struct st_mi_check_param *param; enum data_file_type new_data_file_type; SORT_KEY_BLOCKS *key_block,*key_block_end; - uint key,find_length; + uint key,find_length,real_key_length; my_off_t pos,max_pos,filepos,start_recpos,filelength,dupp,buff_length; ha_rows max_records; ulonglong unique[MI_MAX_KEY_SEG+1]; my_bool fix_datafile; char *record,*buff; + void *wordlist, *wordptr; MI_KEYDEF *keyinfo; MI_KEYSEG *keyseg; } SORT_INFO; - typedef struct st_mi_check_param { ulonglong auto_increment_value; diff --git a/include/mysql.h b/include/mysql.h index b5d918a98af..7db907fb0f3 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -15,8 +15,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -/* defines for the libmysql library */ - #ifndef _mysql_h #define _mysql_h @@ -126,15 +124,30 @@ typedef struct st_mysql_data { struct st_mysql_options { unsigned int connect_timeout,client_flag; - my_bool compress,named_pipe; unsigned int port; char *host,*init_command,*user,*password,*unix_socket,*db; char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; - my_bool use_ssl; /* if to use SSL or not */ char *ssl_key; /* PEM key file */ char *ssl_cert; /* PEM cert file */ char *ssl_ca; /* PEM CA file */ char *ssl_capath; /* PEM directory of CA-s? */ + my_bool use_ssl; /* if to use SSL or not */ + my_bool compress,named_pipe; + /* + on connect, find out the replication role of the server, and + establish connections to all the peers + */ + my_bool rpl_probe; + /* + each call to mysql_real_query() will parse it to tell if it is a read + or a write, and direct it to the slave or the master + */ + my_bool rpl_parse; + /* + if set, never read from a master,only from slave, when doing + a read that is replication-aware + */ + my_bool no_master_reads; }; enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, @@ -145,6 +158,15 @@ enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, enum mysql_status { MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT}; +/* + There are three types of queries - the ones that have to go to + the master, the ones that go to a slave, and the adminstrative + type which must happen on the pivot connectioin +*/ +enum mysql_rpl_type { MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, + MYSQL_RPL_ADMIN }; + + typedef struct st_mysql { NET net; /* Communication parameters */ gptr connector_fd; /* ConnectorFd for SSL */ @@ -168,6 +190,19 @@ typedef struct st_mysql { char scramble_buff[9]; struct charset_info_st *charset; unsigned int server_language; + + /* pointers to the master, and the next slave + connections, points to itself if lone connection */ + struct st_mysql* master, *next_slave; + + struct st_mysql* last_used_slave; /* needed for round-robin slave pick */ + /* needed for send/read/store/use result to work correctly with replication */ + struct st_mysql* last_used_con; + /* + Set if this is the original connection, not a master or a slave we have + added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave() + */ + my_bool rpl_pivot; } MYSQL; @@ -185,6 +220,20 @@ typedef struct st_mysql_res { my_bool eof; /* Used my mysql_fetch_row */ } MYSQL_RES; + +/* Set up and bring down the server; to ensure that applications will + * work when linked against either the standard client library or the + * embedded server library, these functions should be called. */ +void mysql_server_init(int argc, char **argv, const char **groups); +void mysql_server_end(); + +/* Set up and bring down a thread; these function should be called + * for each thread in an application which opens at least one MySQL + * connection. All uses of the connection(s) should be between these + * function calls. */ +my_bool mysql_thread_init(); +void mysql_thread_end(); + /* Functions to get information from the MYSQL and MYSQL_RES structures */ /* Should definitely be used if one uses shared libraries */ @@ -207,18 +256,12 @@ unsigned long STDCALL mysql_thread_id(MYSQL *mysql); const char * STDCALL mysql_character_set_name(MYSQL *mysql); MYSQL * STDCALL mysql_init(MYSQL *mysql); -#ifdef HAVE_OPENSSL int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath); -char * STDCALL mysql_ssl_cipher(MYSQL *mysql); int STDCALL mysql_ssl_clear(MYSQL *mysql); -#endif /* HAVE_OPENSSL */ -MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, - const char *user, const char *passwd); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db); -#if MYSQL_VERSION_ID >= 32200 MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, @@ -226,14 +269,6 @@ MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, unsigned int port, const char *unix_socket, unsigned int clientflag); -#else -MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, - const char *user, - const char *passwd, - unsigned int port, - const char *unix_socket, - unsigned int clientflag); -#endif void STDCALL mysql_close(MYSQL *sock); int STDCALL mysql_select_db(MYSQL *mysql, const char *db); int STDCALL mysql_query(MYSQL *mysql, const char *q); @@ -242,8 +277,47 @@ int STDCALL mysql_send_query(MYSQL *mysql, const char *q, int STDCALL mysql_read_query_result(MYSQL *mysql); int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned int length); -int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); -int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); +/* perform query on master */ +int STDCALL mysql_master_query(MYSQL *mysql, const char *q, + unsigned int length); +int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned int length); +/* perform query on slave */ +int STDCALL mysql_slave_query(MYSQL *mysql, const char *q, + unsigned int length); +int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, + unsigned int length); + +/* + enable/disable parsing of all queries to decide if they go on master or + slave +*/ +void STDCALL mysql_enable_rpl_parse(MYSQL* mysql); +void STDCALL mysql_disable_rpl_parse(MYSQL* mysql); +/* get the value of the parse flag */ +int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql); + +/* enable/disable reads from master */ +void STDCALL mysql_enable_reads_from_master(MYSQL* mysql); +void STDCALL mysql_disable_reads_from_master(MYSQL* mysql); +/* get the value of the master read flag */ +int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql); + +enum mysql_rpl_type STDCALL mysql_rpl_query_type(const char* q, int len); + +/* discover the master and its slaves */ +int STDCALL mysql_rpl_probe(MYSQL* mysql); + +/* set the master, close/free the old one, if it is not a pivot */ +int STDCALL mysql_set_master(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); +int STDCALL mysql_add_slave(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); + int STDCALL mysql_shutdown(MYSQL *mysql); int STDCALL mysql_dump_debug_info(MYSQL *mysql); int STDCALL mysql_refresh(MYSQL *mysql, @@ -292,10 +366,14 @@ char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); - #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) -/* new api functions */ +#ifdef USE_OLD_FUNCTIONS +MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, + const char *user, const char *passwd); +int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); +int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); +#endif #define HAVE_MYSQL_REAL_CONNECT diff --git a/include/mysql_com.h b/include/mysql_com.h index 2e455c456fa..ce134fcab2c 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -42,7 +42,8 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL, COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, - COM_TABLE_DUMP, COM_CONNECT_OUT}; + COM_TABLE_DUMP, COM_CONNECT_OUT, + COM_REGISTER_SLAVE}; #define NOT_NULL_FLAG 1 /* Field can't be NULL */ #define PRI_KEY_FLAG 2 /* Field is part of a primary key */ @@ -100,15 +101,8 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, #define NET_WRITE_TIMEOUT 60 /* Timeout on write */ #define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ -#ifndef Vio_defined -#define Vio_defined -#ifdef HAVE_VIO -class Vio; /* Fill Vio class in C++ */ -#else struct st_vio; /* Only C */ typedef struct st_vio Vio; -#endif -#endif typedef struct st_net { Vio* vio; @@ -152,11 +146,15 @@ enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY, #define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */ #define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compability */ +#define net_new_transaction(net) ((net)->pkt_nr=0) + +#ifdef __cplusplus +extern "C" { +#endif + extern unsigned long max_allowed_packet; extern unsigned long net_buffer_length; -#define net_new_transaction(net) ((net)->pkt_nr=0) - int my_net_init(NET *net, Vio* vio); void net_end(NET *net); void net_clear(NET *net); @@ -165,13 +163,17 @@ int my_net_write(NET *net,const char *packet,unsigned long len); int net_write_command(NET *net,unsigned char command,const char *packet, unsigned long len); int net_real_write(NET *net,const char *packet,unsigned long len); -unsigned int my_net_read(NET *net); +unsigned long my_net_read(NET *net); struct rand_struct { unsigned long seed1,seed2,max_value; double max_value_dbl; }; +#ifdef __cplusplus +} +#endif + /* The following is for user defined functions */ enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT}; diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 08e621f4a2a..b81e10308ff 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -211,6 +211,13 @@ #define ER_DROP_DB_WITH_READ_LOCK 1208 #define ER_CREATE_DB_WITH_READ_LOCK 1209 #define ER_WRONG_ARGUMENTS 1210 -#define ER_NO_PERMISSON_TO_CREATE_USER 1211 +#define ER_NO_PERMISSION_TO_CREATE_USER 1211 #define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 -#define ER_ERROR_MESSAGES 213 +#define ER_CONNECT_TO_MASTER 1213 +#define ER_QUERY_ON_MASTER 1214 +#define ER_ERROR_WHEN_EXECUTING_COMMAND 1215 +#define ER_WRONG_USAGE 1216 +#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1217 +#define ER_CANT_UPDATE_WITH_READLOCK 1218 +#define ER_MIXING_NOT_ALLOWED 1219 +#define ER_ERROR_MESSAGES 220 diff --git a/include/violite.h b/include/violite.h index 49df6994d53..49791c6b68a 100644 --- a/include/violite.h +++ b/include/violite.h @@ -25,9 +25,6 @@ #include "my_net.h" /* needed because of struct in_addr */ -#ifdef HAVE_VIO -#include <Vio.h> /* Full VIO interface */ -#else /* Simple vio interface in C; The functions are implemented in violite.c */ @@ -35,14 +32,12 @@ extern "C" { #endif /* __cplusplus */ -#ifndef Vio_defined -#define Vio_defined -struct st_vio; /* Only C */ -typedef struct st_vio Vio; -#endif - enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, - VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL}; + VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL}; + +#ifndef __WIN__ +#define HANDLE void * +#endif Vio* vio_new(my_socket sd, enum enum_vio_type type, @@ -52,6 +47,14 @@ Vio* vio_new_win32pipe(HANDLE hPipe); #endif void vio_delete(Vio* vio); +#ifdef EMBEDDED_LIBRARY +void vio_reset(Vio *vio); +#else +void vio_reset(Vio* vio, enum enum_vio_type type, + my_socket sd, HANDLE hPipe, + my_bool localhost); +#endif + /* * vio_read and vio_write should have the same semantics * as read(2) and write(2). @@ -83,7 +86,7 @@ my_bool vio_should_retry( Vio* vio); /* * When the workday is over... */ -int vio_close( Vio* vio); +int vio_close(Vio* vio); /* * Short text description of the socket for those, who are curious.. */ @@ -93,15 +96,15 @@ const char* vio_description( Vio* vio); enum enum_vio_type vio_type(Vio* vio); /* Return last error number */ -int vio_errno(Vio *vio); +int vio_errno(Vio*vio); /* Get socket number */ -my_socket vio_fd(Vio *vio); +my_socket vio_fd(Vio*vio); /* * Remote peer's address and name in text form. */ -my_bool vio_peer_addr(Vio * vio, char *buf); +my_bool vio_peer_addr(Vio* vio, char *buf); /* Remotes in_addr */ @@ -113,5 +116,140 @@ my_bool vio_poll_read(Vio *vio,uint timeout); #ifdef __cplusplus } #endif -#endif /* HAVE_VIO */ #endif /* vio_violite_h_ */ +#ifdef HAVE_VIO +#ifndef DONT_MAP_VIO +#define vio_delete(vio) (vio)->viodelete(vio) +#define vio_errno(vio) (vio)->vioerrno(vio) +#define vio_read(vio, buf, size) (vio)->read(vio,buf,size) +#define vio_write(vio, buf, size) (vio)->write(vio, buf, size) +#define vio_blocking(vio, set_blocking_mode) (vio)->vioblocking(vio, set_blocking_mode) +#define vio_is_blocking(vio) (vio)->is_blocking(vio) +#define vio_fastsend(vio) (vio)->fastsend(vio) +#define vio_keepalive(vio, set_keep_alive) (vio)->viokeepalive(vio, set_keep_alive) +#define vio_should_retry(vio) (vio)->should_retry(vio) +#define vio_close(vio) ((vio)->vioclose)(vio) +#define vio_peer_addr(vio, buf) (vio)->peer_addr(vio, buf) +#define vio_in_addr(vio, in) (vio)->in_addr(vio, in) +#define vio_poll_read(vio,timeout) (vio)->poll_read(vio,timeout) +#endif /* !DONT_MAP_VIO */ +#endif /* HAVE_VIO */ + + +#ifdef HAVE_OPENSSL +#define HEADER_DES_LOCL_H dummy_something +#include <openssl/ssl.h> +#include <openssl/err.h> +#include "my_net.h" /* needed because of struct in_addr */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void vio_ssl_delete(Vio* vio); + +int vio_ssl_read(Vio* vio,gptr buf, int size); +int vio_ssl_write(Vio* vio,const gptr buf,int size); +int vio_ssl_blocking(Vio* vio,my_bool onoff); +my_bool vio_ssl_is_blocking(Vio* vio); + +/* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible. */ + int vio_ssl_fastsend(Vio* vio); +/* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible. */ +int vio_ssl_keepalive(Vio* vio, my_bool onoff); +/* Whenever we should retry the last read/write operation. */ +my_bool vio_ssl_should_retry(Vio* vio); +/* When the workday is over... */ +int vio_ssl_close(Vio* vio); +/* Return last error number */ +int vio_ssl_errno(Vio *vio); +my_bool vio_ssl_peer_addr(Vio* vio, char *buf); +void vio_ssl_in_addr(Vio *vio, struct in_addr *in); + +/* Return 1 if there is data to be read */ +my_bool vio_ssl_poll_read(Vio *vio,uint timeout); + +#ifdef HAVE_OPENSSL + +/* Single copy for server */ +struct st_VioSSLAcceptorFd +{ + SSL_CTX* ssl_context_; + SSL_METHOD* ssl_method_; + struct st_VioSSLAcceptorFd* session_id_context_; + enum { + state_connect = 1, + state_accept = 2 + }; +// BIO* bio_; +// char desc_[100]; +// Vio* sd_; + + /* function pointers which are only once for SSL server + Vio*(*sslaccept)(struct st_VioSSLAcceptorFd*,Vio*); */ +}; + +/* One copy for client */ +struct st_VioSSLConnectorFd +{ + SSL_CTX* ssl_context_; + SSL_METHOD* ssl_method_; + /* function pointers which are only once for SSL client */ +}; +void sslaccept(struct st_VioSSLAcceptorFd*, Vio*); +void sslconnect(struct st_VioSSLConnectorFd*, Vio*); + +#else /* HAVE_OPENSSL */ +/* This dummy is required to maintain proper size of st_mysql in mysql.h */ +struct st_VioSSLConnectorFd {}; +#endif /* HAVE_OPENSSL */ +struct st_VioSSLConnectorFd *new_VioSSLConnectorFd( + const char* key_file,const char* cert_file,const char* ca_file,const char* ca_path); +struct st_VioSSLAcceptorFd *new_VioSSLAcceptorFd( + const char* key_file,const char* cert_file,const char* ca_file,const char* ca_path); +Vio* new_VioSSL(struct st_VioSSLAcceptorFd* fd, Vio* sd,int state); + +#ifdef __cplusplus +} +#endif +#endif /* HAVE_OPENSSL */ + +#ifndef EMBEDDED_LIBRARY +/* This structure is for every connection on both sides */ +struct st_vio +{ + my_socket sd; /* my_socket - real or imaginary */ + HANDLE hPipe; + my_bool localhost; /* Are we from localhost? */ + int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ + struct sockaddr_in local; /* Local internet address */ + struct sockaddr_in remote; /* Remote internet address */ + enum enum_vio_type type; /* Type of connection */ + char desc[30]; /* String description */ +#ifdef HAVE_VIO + /* function pointers. They are similar for socket/SSL/whatever */ + void (*viodelete)(Vio*); + int(*vioerrno)(Vio*); + int(*read)(Vio*, gptr, int); + int(*write)(Vio*, gptr, int); + int(*vioblocking)(Vio*, my_bool); + my_bool(*is_blocking)(Vio*); + int(*viokeepalive)(Vio*, my_bool); + int(*fastsend)(Vio*); + my_bool(*peer_addr)(Vio*, gptr); + void(*in_addr)(Vio*, struct in_addr*); + my_bool(*should_retry)(Vio*); + int(*vioclose)(Vio*); + my_bool(*poll_read)(Vio*,uint); + +#ifdef HAVE_OPENSSL + BIO* bio_; + SSL* ssl_; + my_bool open_; + char *ssl_cip_; +#endif /* HAVE_OPENSSL */ +#endif /* HAVE_VIO */ +}; +#endif /* EMBEDDED_LIBRARY */ + diff --git a/isam/extra.c b/isam/extra.c index 1d333fa372f..d5769101b8f 100644 --- a/isam/extra.c +++ b/isam/extra.c @@ -204,6 +204,7 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) info->s->changed=1; /* Update on close */ break; case HA_EXTRA_FORCE_REOPEN: + case HA_EXTRA_PREPARE_FOR_DELETE: pthread_mutex_lock(&THR_LOCK_isam); info->s->last_version= 0L; /* Impossible version */ #ifdef __WIN__ diff --git a/isam/isamlog.c b/isam/isamlog.c index 5763b697d07..6fc5d98cc76 100644 --- a/isam/isamlog.c +++ b/isam/isamlog.c @@ -327,8 +327,8 @@ static int examine_log(my_string file_name, char **table_names) init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0)); bzero((gptr) com_count,sizeof(com_count)); - init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1, - (void(*)(void*)) file_info_free); + init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1, + (tree_element_free) file_info_free, NULL); VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD)))); files_open=0; access_time=0; diff --git a/isam/pack_isam.c b/isam/pack_isam.c index c2cbb72cf74..b8814527af2 100644 --- a/isam/pack_isam.c +++ b/isam/pack_isam.c @@ -684,7 +684,7 @@ static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIPP_ZERO)) count[i].max_zero_fill= count[i].field_length; - init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL); + init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL); if (records) count[i].tree_pos=count[i].tree_buff = my_malloc(count[i].field_length > 1 ? tree_buff_length : 2, diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index 01cc438a72b..02291d75e7c 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -21,7 +21,7 @@ target = libmysqlclient.la target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID LIBS = @CLIENT_LIBS@ INCLUDES = -I$(srcdir)/../include -I../include \ - -I$(srcdir)/.. -I$(top_srcdir) -I.. + -I$(srcdir)/.. -I$(top_srcdir) -I.. $(openssl_includes) include $(srcdir)/Makefile.shared @@ -36,14 +36,23 @@ link_sources: ss=`echo $(mystringsobjects) | sed "s;\.lo;.c;g"`; \ ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \ ms=`echo $(mysysobjects) | sed "s;\.lo;.c;g"`; \ + vs=`echo $(vio_objects) | sed "s;\.lo;.c;g"`; \ for f in $$ss; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ done; \ + for f in $$vs; do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(srcdir)/../vio/$$f $(srcdir)/$$f; \ + done; \ for f in $(mystringsextra); do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ done; \ + for f in $$qs; do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \ + done; \ for f in $$ds; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index e9e100e38b1..8513b92624e 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -31,7 +31,7 @@ noinst_PROGRAMS = conf_to_src CHARSET_OBJS=@CHARSET_OBJS@ LTCHARSET_OBJS= ${CHARSET_OBJS:.o=.lo} -target_sources = libmysql.c net.c violite.c password.c \ +target_sources = libmysql.c net.c password.c \ get_password.c errmsg.c mystringsobjects = strmov.lo strxmov.lo strnmov.lo strmake.lo strend.lo \ @@ -56,12 +56,15 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ thr_mutex.lo mulalloc.lo string.lo default.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \ charset.lo hash.lo mf_iocache.lo my_seek.lo \ - my_pread.lo mf_cache.lo + my_pread.lo mf_cache.lo my_vsnprintf.lo + # Not needed in the minimum library mysysobjects2 = getopt.lo getopt1.lo getvar.lo my_lib.lo mysysobjects = $(mysysobjects1) $(mysysobjects2) -target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) +target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \ + $(vio_objects) target_ldflags = -version-info @SHARED_LIB_VERSION@ +vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo CLEANFILES = $(target_libadd) $(SHLIBOBJS) \ $(target) DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \ @@ -76,6 +79,7 @@ clean-local: rm -f `echo $(mystringsobjects) | sed "s;\.lo;.c;g"` \ `echo $(dbugobjects) | sed "s;\.lo;.c;g"` \ `echo $(mysysobjects) | sed "s;\.lo;.c;g"` \ + `echo $(vio_objects) | sed "s;\.lo;.c;g"` \ $(mystringsextra) $(mysysheaders) ctype_extra_sources.c \ ../linked_client_sources diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 67cfe874f77..55e2f8164ed 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -16,7 +16,7 @@ MA 02111-1307, USA */ /* Error messages for MySQL clients */ -/* error messages for the demon is in share/language/errmsg.sys */ +/* error messages for the daemon is in share/language/errmsg.sys */ #include <global.h> #include <my_sys.h> @@ -45,7 +45,12 @@ const char *client_errors[]= "Kann Named Pipe nicht oeffnen. Host: %-.64s pipe: %-.32s (%lu)", "Kann den Status der Named Pipe nicht setzen. Host: %-.64s pipe: %-.32s (%lu)", "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'" + "Got packet bigger than 'max_allowed_packet'", + "Embedded server", + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" }; /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ @@ -73,7 +78,12 @@ const char *client_errors[]= "Não pode abrir 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", "Não pode estabelecer o estado do 'named pipe' para o 'host' %-.64s - 'pipe' %-.32s (%lu)", "Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)", - "Obteve pacote maior do que 'max_allowed_packet'" + "Obteve pacote maior do que 'max_allowed_packet'", + "Embedded server" + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" }; #else /* ENGLISH */ @@ -99,7 +109,12 @@ const char *client_errors[]= "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)", "Can't initialize character set %-.64s (path: %-.64s)", - "Got packet bigger than 'max_allowed_packet'" + "Got packet bigger than 'max_allowed_packet'", + "Embedded server", + "Error on SHOW SLAVE STATUS:", + "Error on SHOW SLAVE HOSTS:", + "Error connecting to slave:", + "Error connecting to master:" }; #endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 0e202a4fc08..e7705ee20e4 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -91,6 +91,28 @@ static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); +void mysql_server_init(int argc __attribute__((unused)), + char **argv __attribute__((unused)), + const char **groups __attribute__((unused))) {} + +void mysql_server_end() {} + +my_bool mysql_thread_init() +{ +#ifdef THREAD + return my_thread_init(); +#else + return 0; +#endif +} + +void mysql_thread_end() +{ +#ifdef THREAD + my_thread_end(); +#endif +} + /* Let the user specify that we don't want SIGPIPE; This doesn't however work with threaded applications as we can have multiple read in progress. @@ -106,6 +128,12 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, #define reset_sigpipe(mysql) #endif +static MYSQL* spawn_init(MYSQL* parent, const char* host, + unsigned int port, + const char* user, + const char* passwd); + + /**************************************************************************** * A modified version of connect(). connect2() allows you to specify * a timeout value, in seconds, that we should wait until we @@ -313,17 +341,9 @@ net_safe_read(MYSQL *mysql) if (len > 3) { char *pos=(char*) net->read_pos+1; - if (mysql->protocol_version > 9) - { /* New client protocol */ - net->last_errno=uint2korr(pos); - pos+=2; - len-=2; - } - else - { - net->last_errno=CR_UNKNOWN_ERROR; - len--; - } + net->last_errno=uint2korr(pos); + pos+=2; + len-=2; (void) strmake(net->last_error,(char*) pos, min(len,sizeof(net->last_error)-1)); } @@ -675,7 +695,8 @@ static const char *default_options[]= "init-command", "host", "database", "debug", "return-found-rows", "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath", "character-set-dir", "default-character-set", "interactive-timeout", - "connect_timeout", + "connect_timeout", "replication-probe", "enable-reads-from-master", + "repl-parse-query", NullS }; @@ -809,6 +830,15 @@ static void mysql_read_default_options(struct st_mysql_options *options, case 19: /* Interactive-timeout */ options->client_flag|=CLIENT_INTERACTIVE; break; + case 21: /* replication probe */ + options->rpl_probe = 1; + break; + case 22: /* enable-reads-from-master */ + options->rpl_parse = 1; + break; + case 23: /* repl-parse-query */ + options->no_master_reads = 0; + break; default: DBUG_PRINT("warning",("unknown option: %s",option[0])); } @@ -984,6 +1014,273 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) return 0; } +/* perform query on master */ +int STDCALL mysql_master_query(MYSQL *mysql, const char *q, + unsigned int length) +{ + if(mysql_master_send_query(mysql, q, length)) + return 1; + return mysql_read_query_result(mysql); +} + +int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned int length) +{ + MYSQL*master = mysql->master; + if (!length) + length = strlen(q); + if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0)) + return 1; + mysql->last_used_con = master; + return simple_command(master, COM_QUERY, q, length, 1); +} + + +/* perform query on slave */ +int STDCALL mysql_slave_query(MYSQL *mysql, const char *q, + unsigned int length) +{ + if(mysql_slave_send_query(mysql, q, length)) + return 1; + return mysql_read_query_result(mysql); +} + +int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, + unsigned int length) +{ + MYSQL* last_used_slave, *slave_to_use = 0; + + if((last_used_slave = mysql->last_used_slave)) + slave_to_use = last_used_slave->next_slave; + else + slave_to_use = mysql->next_slave; + /* next_slave is always safe to use - we have a circular list of slaves + if there are no slaves, mysql->next_slave == mysql + */ + mysql->last_used_con = mysql->last_used_slave = slave_to_use; + if(!length) + length = strlen(q); + if(!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0, + 0,0,0,0)) + return 1; + return simple_command(slave_to_use, COM_QUERY, q, length, 1); +} + + +/* enable/disable parsing of all queries to decide + if they go on master or slave */ +void STDCALL mysql_enable_rpl_parse(MYSQL* mysql) +{ + mysql->options.rpl_parse = 1; +} + +void STDCALL mysql_disable_rpl_parse(MYSQL* mysql) +{ + mysql->options.rpl_parse = 0; +} + +/* get the value of the parse flag */ +int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql) +{ + return mysql->options.rpl_parse; +} + +/* enable/disable reads from master */ +void STDCALL mysql_enable_reads_from_master(MYSQL* mysql) +{ + mysql->options.no_master_reads = 0; +} + +void STDCALL mysql_disable_reads_from_master(MYSQL* mysql) +{ + mysql->options.no_master_reads = 1; +} + +/* get the value of the master read flag */ +int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql) +{ + return !(mysql->options.no_master_reads); +} + +/* We may get an error while doing replication internals. + In this case, we add a special explanation to the original + error +*/ +static inline void expand_error(MYSQL* mysql, int error) +{ + char tmp[MYSQL_ERRMSG_SIZE]; + char* p, *tmp_end; + tmp_end = strnmov(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE); + p = strnmov(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE); + memcpy(p, tmp, tmp_end - tmp); + mysql->net.last_errno = error; +} + +/* This function assumes we have just called SHOW SLAVE STATUS and have + read the given result and row +*/ +static inline int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row) +{ + MYSQL* master; + if(mysql_num_fields(res) < 3) + return 1; /* safety */ + + /* use the same username and password as the original connection */ + if(!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0))) + return 1; + mysql->master = master; + return 0; +} + +/* assuming we already know that mysql points to a master connection, + retrieve all the slaves +*/ +static inline int get_slaves_from_master(MYSQL* mysql) +{ + MYSQL_RES* res = 0; + MYSQL_ROW row; + int error = 1; + int has_auth_info; + if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0)) + { + expand_error(mysql, CR_PROBE_MASTER_CONNECT); + return 1; + } + + if (mysql_query(mysql, "SHOW SLAVE HOSTS") || + !(res = mysql_store_result(mysql))) + { + expand_error(mysql, CR_PROBE_SLAVE_HOSTS); + return 1; + } + + switch (mysql_num_fields(res)) + { + case 3: has_auth_info = 0; break; + case 5: has_auth_info = 1; break; + default: + goto err; + } + + while ((row = mysql_fetch_row(res))) + { + MYSQL* slave; + const char* tmp_user, *tmp_pass; + + if (has_auth_info) + { + tmp_user = row[3]; + tmp_pass = row[4]; + } + else + { + tmp_user = mysql->user; + tmp_pass = mysql->passwd; + } + + if(!(slave = spawn_init(mysql, row[1], atoi(row[2]), + tmp_user, tmp_pass))) + goto err; + + /* Now add slave into the circular linked list */ + slave->next_slave = mysql->next_slave; + mysql->next_slave = slave; + } + error = 0; +err: + if(res) + mysql_free_result(res); + return error; +} + +int STDCALL mysql_rpl_probe(MYSQL* mysql) +{ + MYSQL_RES* res = 0; + MYSQL_ROW row; + int error = 1; + /* first determine the replication role of the server we connected to + the most reliable way to do this is to run SHOW SLAVE STATUS and see + if we have a non-empty master host. This is still not fool-proof - + it is not a sin to have a master that has a dormant slave thread with + a non-empty master host. However, it is more reliable to check + for empty master than whether the slave thread is actually running + */ + if (mysql_query(mysql, "SHOW SLAVE STATUS") || + !(res = mysql_store_result(mysql))) + { + expand_error(mysql, CR_PROBE_SLAVE_STATUS); + return 1; + } + + if (!(row = mysql_fetch_row(res))) + goto err; + + /* check master host for emptiness/NULL */ + if (row[0] && *(row[0])) + { + /* this is a slave, ask it for the master */ + if (get_master(mysql, res, row) || get_slaves_from_master(mysql)) + goto err; + } + else + { + mysql->master = mysql; + if (get_slaves_from_master(mysql)) + goto err; + } + + error = 0; +err: + if(res) + mysql_free_result(res); + return error; +} + + +/* make a not so fool-proof decision on where the query should go, to + the master or the slave. Ideally the user should always make this + decision himself with mysql_master_query() or mysql_slave_query(). + However, to be able to more easily port the old code, we support the + option of an educated guess - this should work for most applications, + however, it may make the wrong decision in some particular cases. If + that happens, the user would have to change the code to call + mysql_master_query() or mysql_slave_query() explicitly in the place + where we have made the wrong decision +*/ +enum mysql_rpl_type +STDCALL mysql_rpl_query_type(const char* q, int len) +{ + const char* q_end; + q_end = (len) ? q + len : strend(q); + for(; q < q_end; ++q) + { + char c; + if(isalpha(c=*q)) + switch(tolower(c)) + { + case 'i': /* insert */ + case 'u': /* update or unlock tables */ + case 'l': /* lock tables or load data infile */ + case 'd': /* drop or delete */ + case 'a': /* alter */ + return MYSQL_RPL_MASTER; + case 'c': /* create or check */ + return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ; + case 's': /* select or show */ + return tolower(q[1] == 'h') ? MYSQL_RPL_ADMIN : MYSQL_RPL_SLAVE; + case 'f': /* flush */ + case 'r': /* repair */ + case 'g': /* grant */ + return MYSQL_RPL_ADMIN; + default: + return MYSQL_RPL_SLAVE; + } + } + + return 0; +} + + /**************************************************************************** ** Init MySQL structure or allocate one ****************************************************************************/ @@ -1002,6 +1299,12 @@ mysql_init(MYSQL *mysql) else bzero((char*) (mysql),sizeof(*(mysql))); mysql->options.connect_timeout=CONNECT_TIMEOUT; + mysql->last_used_con = mysql->next_slave = mysql->master = mysql; + mysql->last_used_slave = 0; + /* By default, we are a replication pivot. The caller must reset it + after we return if this is not the case. + */ + mysql->rpl_pivot = 1; #if defined(SIGPIPE) && defined(THREAD) if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE)) (void) signal(SIGPIPE,pipe_sig_handler); @@ -1053,43 +1356,40 @@ static void mysql_once_init() #endif } -#ifdef HAVE_OPENSSL /************************************************************************** ** Fill in SSL part of MYSQL structure and set 'use_ssl' flag. ** NB! Errors are not reported until you do mysql_real_connect. **************************************************************************/ int STDCALL -mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, - const char *ca, const char *capath) +mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , + const char *key __attribute__((unused)), + const char *cert __attribute__((unused)), + const char *ca __attribute__((unused)), + const char *capath __attribute__((unused))) { +#ifdef HAVE_OPENSSL mysql->options.ssl_key = key==0 ? 0 : my_strdup(key,MYF(0)); mysql->options.ssl_cert = cert==0 ? 0 : my_strdup(cert,MYF(0)); mysql->options.ssl_ca = ca==0 ? 0 : my_strdup(ca,MYF(0)); mysql->options.ssl_capath = capath==0 ? 0 : my_strdup(capath,MYF(0)); - mysql->options.use_ssl = true; - mysql->connector_fd = new_VioSSLConnectorFd(key, cert, ca, capath); + mysql->options.use_ssl = TRUE; + mysql->connector_fd = (gptr)new_VioSSLConnectorFd(key, cert, ca, capath); + DBUG_PRINT("info",("mysql_ssl_set, context: %p",((struct st_VioSSLConnectorFd *)(mysql->connector_fd))->ssl_context_)); +#endif return 0; } -/************************************************************************** -**************************************************************************/ - -char * STDCALL -mysql_ssl_cipher(MYSQL *mysql) -{ - return (char *)mysql->net.vio->cipher_description(); -} - - -/************************************************************************** +/* +*************************************************************************** ** Free strings in the SSL structure and clear 'use_ssl' flag. ** NB! Errors are not reported until you do mysql_real_connect. -**************************************************************************/ - +************************************************************************** +*/ int STDCALL -mysql_ssl_clear(MYSQL *mysql) +mysql_ssl_clear(MYSQL *mysql __attribute__((unused))) { +#ifdef HAVE_OPENSSL my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); @@ -1098,18 +1398,19 @@ mysql_ssl_clear(MYSQL *mysql) mysql->options.ssl_cert = 0; mysql->options.ssl_ca = 0; mysql->options.ssl_capath = 0; - mysql->options.use_ssl = false; - mysql->connector_fd->delete(); + mysql->options.use_ssl = FALSE; + my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR)); mysql->connector_fd = 0; +#endif /* HAVE_OPENSSL */ return 0; } -#endif /* HAVE_OPENSSL */ /************************************************************************** ** Connect to sql server ** If host == 0 then use localhost **************************************************************************/ +#ifdef USE_OLD_FUNCTIONS MYSQL * STDCALL mysql_connect(MYSQL *mysql,const char *host, const char *user, const char *passwd) @@ -1126,6 +1427,7 @@ mysql_connect(MYSQL *mysql,const char *host, DBUG_RETURN(res); } } +#endif /* @@ -1357,8 +1659,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, DBUG_DUMP("packet",(char*) net->read_pos,10); DBUG_PRINT("info",("mysql protocol version %d, server=%d", PROTOCOL_VERSION, mysql->protocol_version)); - if (mysql->protocol_version != PROTOCOL_VERSION && - mysql->protocol_version != PROTOCOL_VERSION-1) + if (mysql->protocol_version != PROTOCOL_VERSION) { net->last_errno= CR_VERSION_ERROR; sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version, @@ -1493,11 +1794,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, goto error; /* Do the SSL layering. */ DBUG_PRINT("info", ("IO layer change in progress...")); - VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*) - (mysql->connector_fd); - VioSocket* vio_socket = (VioSocket*)(mysql->net.vio); - VioSSL* vio_ssl = connector_fd->connect(vio_socket); - mysql->net.vio = (NetVio*)(vio_ssl); + DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_)); + sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio); + DBUG_PRINT("info", ("IO layer change done!")); } #endif /* HAVE_OPENSSL */ @@ -1539,6 +1838,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->reconnect=reconnect; } + if (mysql->options.rpl_probe && mysql_rpl_probe(mysql)) + goto error; + DBUG_PRINT("exit",("Mysql handler: %lx",mysql)); reset_sigpipe(mysql); DBUG_RETURN(mysql); @@ -1557,6 +1859,23 @@ error: DBUG_RETURN(0); } +/* needed when we move MYSQL structure to a different address */ +static void mysql_fix_pointers(MYSQL* mysql, MYSQL* old_mysql) +{ + MYSQL *tmp, *tmp_prev; + if (mysql->master == old_mysql) + mysql->master = mysql; + if (mysql->last_used_con == old_mysql) + mysql->last_used_con = mysql; + if (mysql->last_used_slave == old_mysql) + mysql->last_used_slave = mysql; + for (tmp_prev = mysql, tmp = mysql->next_slave; + tmp != old_mysql;tmp = tmp->next_slave) + { + tmp_prev = tmp; + } + tmp_prev->next_slave = mysql; +} static my_bool mysql_reconnect(MYSQL *mysql) { @@ -1572,6 +1891,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) } mysql_init(&tmp_mysql); tmp_mysql.options=mysql->options; + tmp_mysql.rpl_pivot = mysql->rpl_pivot; if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, mysql->client_flag)) @@ -1581,6 +1901,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) bzero((char*) &mysql->options,sizeof(mysql->options)); mysql_close(mysql); *mysql=tmp_mysql; + mysql_fix_pointers(mysql, &tmp_mysql); /* adjust connection pointers */ net_clear(&mysql->net); mysql->affected_rows= ~(my_ulonglong) 0; DBUG_RETURN(0); @@ -1677,9 +1998,23 @@ mysql_close(MYSQL *mysql) bzero((char*) &mysql->options,sizeof(mysql->options)); mysql->net.vio = 0; #ifdef HAVE_OPENSSL - ((VioConnectorFd*)(mysql->connector_fd))->delete(); - mysql->connector_fd = 0; + mysql_ssl_clear(mysql); #endif /* HAVE_OPENSSL */ + + /* free/close slave list */ + if (mysql->rpl_pivot) + { + MYSQL* tmp; + for (tmp = mysql->next_slave; tmp != mysql; ) + { + /* trick to avoid following freed pointer */ + MYSQL* tmp1 = tmp->next_slave; + mysql_close(tmp); + tmp = tmp1; + } + } + if(mysql != mysql->master) + mysql_close(mysql->master); if (mysql->free_me) my_free((gptr) mysql,MYF(0)); } @@ -1698,6 +2033,67 @@ mysql_query(MYSQL *mysql, const char *query) return mysql_real_query(mysql,query, (uint) strlen(query)); } +static MYSQL* spawn_init(MYSQL* parent, const char* host, + unsigned int port, + const char* user, + const char* passwd) +{ + MYSQL* child; + if (!(child = mysql_init(0))) + return 0; + + child->options.user = my_strdup((user) ? user : + (parent->user ? parent->user : + parent->options.user), MYF(0)); + child->options.password = my_strdup((passwd) ? passwd : (parent->passwd ? + parent->passwd : + parent->options.password), MYF(0)); + child->options.port = port; + child->options.host = my_strdup((host) ? host : (parent->host ? + parent->host : + parent->options.host), MYF(0)); + if(parent->db) + child->options.db = my_strdup(parent->db, MYF(0)); + else if(parent->options.db) + child->options.db = my_strdup(parent->options.db, MYF(0)); + + child->options.rpl_parse = child->options.rpl_probe = child->rpl_pivot = 0; + + return child; +} + + +int +STDCALL mysql_set_master(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd) +{ + if (mysql->master != mysql && !mysql->master->rpl_pivot) + mysql_close(mysql->master); + if(!(mysql->master = spawn_init(mysql, host, port, user, passwd))) + return 1; + mysql->master->rpl_pivot = 0; + mysql->master->options.rpl_parse = 0; + mysql->master->options.rpl_probe = 0; + return 0; +} + +int +STDCALL mysql_add_slave(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd) +{ + MYSQL* slave; + if(!(slave = spawn_init(mysql, host, port, user, passwd))) + return 1; + slave->next_slave = mysql->next_slave; + mysql->next_slave = slave; + return 0; +} + + /* Send the query and return so we can do something else. Needs to be followed by mysql_read_query_result() when we want to @@ -1707,6 +2103,20 @@ mysql_query(MYSQL *mysql, const char *query) int STDCALL mysql_send_query(MYSQL* mysql, const char* query, uint length) { + if (mysql->options.rpl_parse && mysql->rpl_pivot) + { + switch (mysql_rpl_query_type(query, length)) + { + case MYSQL_RPL_MASTER: + return mysql_master_send_query(mysql, query, length); + case MYSQL_RPL_SLAVE: + return mysql_slave_send_query(mysql, query, length); + case MYSQL_RPL_ADMIN: /*fall through */ + } + } + + mysql->last_used_con = mysql; + return simple_command(mysql, COM_QUERY, query, length, 1); } @@ -1718,6 +2128,11 @@ int STDCALL mysql_read_query_result(MYSQL *mysql) uint length; DBUG_ENTER("mysql_read_query_result"); + /* read from the connection which we actually used, which + could differ from the original connection if we have slaves + */ + mysql = mysql->last_used_con; + if ((length = net_safe_read(mysql)) == packet_error) DBUG_RETURN(-1); free_old_query(mysql); /* Free old result */ @@ -1764,7 +2179,8 @@ mysql_real_query(MYSQL *mysql, const char *query, uint length) DBUG_ENTER("mysql_real_query"); DBUG_PRINT("enter",("handle: %lx",mysql)); DBUG_PRINT("query",("Query = \"%s\"",query)); - if (simple_command(mysql,COM_QUERY,query,length,1)) + + if (mysql_send_query(mysql,query,length)) DBUG_RETURN(-1); DBUG_RETURN(mysql_read_query_result(mysql)); } @@ -1836,6 +2252,9 @@ mysql_store_result(MYSQL *mysql) MYSQL_RES *result; DBUG_ENTER("mysql_store_result"); + /* read from the actually used connection */ + mysql = mysql->last_used_con; + if (!mysql->fields) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) @@ -1888,6 +2307,8 @@ mysql_use_result(MYSQL *mysql) MYSQL_RES *result; DBUG_ENTER("mysql_use_result"); + mysql = mysql->last_used_con; + if (!mysql->fields) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) @@ -2151,6 +2572,7 @@ mysql_list_processes(MYSQL *mysql) } +#ifdef USE_OLD_FUNCTIONS int STDCALL mysql_create_db(MYSQL *mysql, const char *db) { @@ -2167,6 +2589,7 @@ mysql_drop_db(MYSQL *mysql, const char *db) DBUG_PRINT("enter",("db: %s",db)); DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0)); } +#endif int STDCALL @@ -2341,32 +2764,32 @@ uint STDCALL mysql_field_tell(MYSQL_RES *res) unsigned int STDCALL mysql_field_count(MYSQL *mysql) { - return mysql->field_count; + return mysql->last_used_con->field_count; } my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) { - return (mysql)->affected_rows; + return mysql->last_used_con->affected_rows; } my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql) { - return (mysql)->insert_id; + return mysql->last_used_con->insert_id; } uint STDCALL mysql_errno(MYSQL *mysql) { - return (mysql)->net.last_errno; + return mysql->net.last_errno; } char * STDCALL mysql_error(MYSQL *mysql) { - return (mysql)->net.last_error; + return mysql->net.last_error; } char *STDCALL mysql_info(MYSQL *mysql) { - return (mysql)->info; + return mysql->info; } ulong STDCALL mysql_thread_id(MYSQL *mysql) diff --git a/libmysql/net.c b/libmysql/net.c index 24e4da3561a..9b9ce1c4048 100644 --- a/libmysql/net.c +++ b/libmysql/net.c @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library 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 Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -22,10 +22,16 @@ ** 3 byte length & 1 byte package-number. */ +#ifdef EMBEDDED_LIBRARY +#define net_read_timeout net_read_timeout1 +#define net_write_timeout net_write_timeout1 +#endif + #ifdef __WIN__ #include <winsock.h> #endif #include <global.h> +#include <mysql_com.h> #include <violite.h> #include <my_sys.h> #include <m_string.h> @@ -34,14 +40,20 @@ #include <signal.h> #include <errno.h> #include <sys/types.h> -#include <violite.h> #ifdef MYSQL_SERVER ulong max_allowed_packet=65536; extern ulong net_read_timeout,net_write_timeout; extern uint test_flags; #else -ulong max_allowed_packet=16*1024*1024L; + +/* +** Give error if a too big packet is found +** The server can change this with the -O switch, but because the client +** can't normally do this the client should have a bigger max_allowed_packet. +*/ + +ulong max_allowed_packet=~0L; ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; #endif @@ -90,28 +102,25 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a #endif #ifdef MYSQL_SERVER -extern ulong bytes_sent, bytes_received; +extern ulong bytes_sent, bytes_received; extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #else #undef statistic_add #define statistic_add(A,B,C) #endif -/* -** Give error if a too big packet is found -** The server can change this with the -O switch, but because the client -** can't normally do this the client should have a bigger max-buffer. -*/ - #define TEST_BLOCKING 8 -static int net_write_buff(NET *net,const char *packet,uint len); +static int net_write_buff(NET *net,const char *packet,ulong len); +#define MAX_THREE_BYTES 255L*255L*255L /* Init with packet info */ int my_net_init(NET *net, Vio* vio) { - if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME)))) + if (!(net->buff=(uchar*) my_malloc(net_buffer_length+ + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) return 1; if (net_buffer_length > max_allowed_packet) max_allowed_packet=net_buffer_length; @@ -158,8 +167,12 @@ static my_bool net_realloc(NET *net, ulong length) net->last_errno=ER_NET_PACKET_TOO_LARGE; return 1; } - pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); - if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME)))) + pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); + /* We must allocate some extra bytes for the end 0 and to be able to + read big compressed blocks */ + if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length + + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) { net->error=1; #ifdef MYSQL_SERVER @@ -215,18 +228,34 @@ int net_flush(NET *net) ** Write something to server/client buffer *****************************************************************************/ - /* ** Write a logical packet with packet header ** Format: Packet length (3 bytes), packet number(1 byte) ** When compression is used a 3 byte compression length is added -** NOTE: If compression is used the original package is destroyed! +** NOTE: If compression is used the original package is modified! */ int my_net_write(NET *net,const char *packet,ulong len) { uchar buff[NET_HEADER_SIZE]; + /* + Big packets are handled by splitting them in packets of MAX_THREE_BYTES + length. The last packet is always a packet that is < MAX_THREE_BYTES. + (The last packet may even have a lengt of 0) + */ + while (len >= MAX_THREE_BYTES) + { + const ulong z_size = MAX_THREE_BYTES; + int3store(buff, z_size); + buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) || + net_write_buff(net, packet, z_size)) + return 1; + packet += z_size; + len-= z_size; + } + /* Write last packet */ int3store(buff,len); buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE)) @@ -234,23 +263,54 @@ my_net_write(NET *net,const char *packet,ulong len) return net_write_buff(net,packet,len); } +/* + Send a command to the server. + As the command is part of the first data packet, we have to do some data + juggling to put the command in there, without having to create a new + packet. + This function will split big packets into sub-packets if needed. + (Each sub packet can only be 2^24 bytes) +*/ + int net_write_command(NET *net,uchar command,const char *packet,ulong len) { - uchar buff[NET_HEADER_SIZE+1]; uint length=len+1; /* 1 extra byte for command */ + uchar buff[NET_HEADER_SIZE+1]; + uint header_size=NET_HEADER_SIZE+1; + buff[4]=command; /* For first packet */ + if (length >= MAX_THREE_BYTES) + { + /* Take into account that we have the command in the first header */ + len= MAX_THREE_BYTES -1; + do + { + int3store(buff, MAX_THREE_BYTES); + buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + if (net_write_buff(net,(char*) buff, header_size) || + net_write_buff(net,packet,len)) + return 1; + packet+= len; + length-= MAX_THREE_BYTES; + len=MAX_THREE_BYTES; + header_size=NET_HEADER_SIZE; + } while (length >= MAX_THREE_BYTES); + len=length; /* Data left to be written */ + } int3store(buff,length); buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); - buff[4]=command; - if (net_write_buff(net,(char*) buff,5)) - return 1; - return test(net_write_buff(net,packet,len) || net_flush(net)); + return test(net_write_buff(net,(char*) buff,header_size) || + net_write_buff(net,packet,len) || net_flush(net)); } +/* + Caching the data in a local buffer before sending it. + One can force the buffer to be flushed with 'net_flush'. +*/ static int -net_write_buff(NET *net,const char *packet,uint len) +net_write_buff(NET *net,const char *packet,ulong len) { uint left_length=(uint) (net->buff_end - net->write_pos); @@ -269,7 +329,11 @@ net_write_buff(NET *net,const char *packet,uint len) return 0; } -/* Read and write using timeouts */ + +/* + Read and write one packet using timeouts. + If needed, the packet is compressed before sending. +*/ int net_real_write(NET *net,const char *packet,ulong len) @@ -439,13 +503,19 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed) } return; } - remain -=(ulong) length; - statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received); + remain -= length; + statistic_add(bytes_received,length,&LOCK_bytes_received); } } #endif /* MYSQL_SERVER */ +/* + Reads one packet to net->buff + net->where_b + Returns length of packet. Long packets are handled by my_net_read(). + This function reallocates the net->buff buffer if necessary. +*/ + static uint my_real_read(NET *net, ulong *complen) { @@ -582,12 +652,13 @@ my_real_read(NET *net, ulong *complen) #endif len=uint3korr(net->buff+net->where_b); + if (!len) /* End of big multi-packet */ + goto end; helping = max(len,*complen) + net->where_b; /* The necessary size of net->buff */ if (helping >= net->max_packet) { - /* We must allocate one extra byte for the end null */ - if (net_realloc(net,helping+1)) + if (net_realloc(net,helping)) { #ifdef MYSQL_SERVER if (i == 1) @@ -612,7 +683,21 @@ end: return(len); } -uint + +/* + Read a packet from the client/server and return it without the internal + package header. + If the packet is the first packet of a multi-packet packet + (which is indicated by the length of the packet = 0xffffff) then + all sub packets are read and concatenated. + If the packet was compressed, its uncompressed and the length of the + uncompressed packet is returned. + + The function returns the length of the found packet or packet_error. + net->read_pos points to the read data. +*/ + +ulong my_net_read(NET *net) { ulong len,complen; @@ -621,65 +706,126 @@ my_net_read(NET *net) if (!net->compress) { #endif - len = my_real_read (net,&complen); + len = my_real_read(net,&complen); + if (len == MAX_THREE_BYTES) + { + /* First packet of a multi-packet. Concatenate the packets */ + int save_pos = net->where_b; + ulong total_length=0; + do + { + net->where_b += len; + total_length += len; + len = my_real_read (net,&complen); + } while (len == MAX_THREE_BYTES); + if (len != packet_error) + len+= total_length; + net->where_b = save_pos; + } net->read_pos = net->buff + net->where_b; if (len != packet_error) net->read_pos[len]=0; /* Safeguard for mysql_use_result */ return len; #ifdef HAVE_COMPRESS } - if (net->remain_in_buf) - net->buff[net->buf_length - net->remain_in_buf]=net->save_char; - for (;;) + else { + /* We are using the compressed protocol */ + + ulong buf_length= net->buf_length; + ulong start_of_packet= net->buf_length - net->remain_in_buf; + ulong first_packet_offset=start_of_packet; + uint read_length, multi_byte_packet=0; + if (net->remain_in_buf) { - uchar *pos = net->buff + net->buf_length - net->remain_in_buf; - if (net->remain_in_buf >= 4) + /* Restore the character that was overwritten by the end 0 */ + net->buff[start_of_packet]=net->save_char; + } + else + { + /* reuse buffer, as there is noting in it that we need */ + buf_length=start_of_packet=first_packet_offset=0; + } + for (;;) + { + ulong packet_len; + + if (buf_length - start_of_packet >= NET_HEADER_SIZE) { - net->length = uint3korr(pos); - if (net->length <= net->remain_in_buf - 4) + read_length = uint3korr(net->buff+start_of_packet); + if (!read_length) + { + /* End of multi-byte packet */ + start_of_packet += NET_HEADER_SIZE; + break; + } + if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet) { - /* We have a full packet */ - len=net->length; - net->remain_in_buf -= net->length + 4; - net->read_pos=pos + 4; - break; /* We have a full packet */ + if (multi_byte_packet) + { + /* Remove packet header for second packet */ + memmove(net->buff + first_packet_offset + start_of_packet, + net->buff + first_packet_offset + start_of_packet + + NET_HEADER_SIZE, + buf_length - start_of_packet); + start_of_packet += read_length; + buf_length -= NET_HEADER_SIZE; + } + else + start_of_packet+= read_length + NET_HEADER_SIZE; + + if (read_length != MAX_THREE_BYTES) /* last package */ + { + multi_byte_packet= 0; // No last zero length packet + break; + } + multi_byte_packet= NET_HEADER_SIZE; + /* Move data down to read next data packet after current one */ + if (first_packet_offset) + { + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; + } + continue; } } /* Move data down to read next data packet after current one */ - if (net->buf_length != net->remain_in_buf) + if (first_packet_offset) { - memmove(net->buff,pos,net->remain_in_buf); - net->buf_length=net->remain_in_buf; + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; } - net->where_b=net->buf_length; - } - else - { - net->where_b=0; - net->buf_length=0; - } - if ((len = my_real_read(net,&complen)) == packet_error) - break; - if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen)) - { - len= packet_error; - net->error=2; /* caller will close socket */ + net->where_b=buf_length; + if ((packet_len = my_real_read(net,&complen)) == packet_error) + return packet_error; + if (my_uncompress((byte*) net->buff + net->where_b, &packet_len, + &complen)) + { + net->error=2; /* caller will close socket */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_UNCOMPRESS_ERROR; + net->last_errno=ER_NET_UNCOMPRESS_ERROR; #endif - break; + return packet_error; + } + buf_length+=packet_len; } - net->buf_length+=len; - net->remain_in_buf+=len; - } - if (len != packet_error) - { + + net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE; + net->buf_length= buf_length; + net->remain_in_buf= buf_length - start_of_packet; + len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE - + multi_byte_packet); net->save_char= net->read_pos[len]; /* Must be saved */ net->read_pos[len]=0; /* Safeguard for mysql_use_result */ } +#endif /* HAVE_COMPRESS */ return len; -#endif } diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am index 92ff5151ad0..88a566bdbf9 100644 --- a/libmysql_r/Makefile.am +++ b/libmysql_r/Makefile.am @@ -22,7 +22,7 @@ target_defs = -DDONT_USE_RAID ## LIBS = @LIBS@ INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include \ - -I$(srcdir)/.. -I$(top_srcdir) -I.. + -I$(srcdir)/.. -I$(top_srcdir) -I.. $(openssl_includes) ## automake barfs if you don't use $(srcdir) or $(top_srcdir) in include include $(top_srcdir)/libmysql/Makefile.shared diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am new file mode 100644 index 00000000000..aaa2b469ccb --- /dev/null +++ b/libmysqld/Makefile.am @@ -0,0 +1,108 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA +# +# This file is public domain and comes with NO WARRANTY of any kind + +MYSQLDATAdir = $(localstatedir) +MYSQLSHAREdir = $(pkgdatadir) +MYSQLBASEdir= $(prefix) + +DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \ + -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \ + -DDATADIR="\"$(MYSQLDATAdir)\"" \ + -DSHAREDIR="\"$(MYSQLSHAREdir)\"" +INCLUDES = @MT_INCLUDES@ @bdb_includes@ -I$(srcdir)/../include -I../include \ + -I$(srcdir)/.. -I$(top_srcdir) -I.. -I../sql -I../regex + + +## XXX: should we use client or server LDFLAGS for libmysqld? +LDADD = @CLIENT_EXTRA_LDFLAGS@ libmysqld.la +pkglib_LTLIBRARIES = libmysqld.la + +libmysqld_la_SOURCES = libmysqld.c lib_sql.cc lib_load.cc + +libmysqlsources = errmsg.c get_password.c password.c +## XXX: we should not have to duplicate info from the sources list +libmysqlobjects = errmsg.lo get_password.lo password.lo + +sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \ + ha_innobase.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \ + ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \ + hostname.cc init.cc \ + item.cc item_buff.cc item_cmpfunc.cc item_create.cc \ + item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \ + item_uniq.cc key.cc lock.cc log.cc log_event.cc md5.c \ + mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \ + opt_sum.cc procedure.cc records.cc slave.cc sql_acl.cc \ + sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ + sql_crypt.cc sql_db.cc sql_delete.cc sql_insert.cc sql_lex.cc \ + sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \ + sql_rename.cc sql_repl.cc sql_select.cc sql_show.cc \ + sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \ + sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ + unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc + +## XXX: we should not have to duplicate info from the sources list +sqlobjects = convert.lo derror.lo field.lo field_conv.lo filesort.lo \ + ha_innobase.lo ha_berkeley.lo ha_heap.lo ha_isam.lo ha_isammrg.lo \ + ha_myisam.lo ha_myisammrg.lo handler.lo sql_handler.lo \ + hostname.lo init.lo \ + item.lo item_buff.lo item_cmpfunc.lo item_create.lo \ + item_func.lo item_strfunc.lo item_sum.lo item_timefunc.lo \ + item_uniq.lo key.lo lock.lo log.lo log_event.lo md5.lo \ + mini_client.lo net_pkg.lo net_serv.lo opt_ft.lo opt_range.lo \ + opt_sum.lo procedure.lo records.lo slave.lo sql_acl.lo \ + sql_analyse.lo sql_base.lo sql_cache.lo sql_class.lo \ + sql_crypt.lo sql_db.lo sql_delete.lo sql_insert.lo sql_lex.lo \ + sql_list.lo sql_manager.lo sql_map.lo sql_parse.lo \ + sql_rename.lo sql_repl.lo sql_select.lo sql_show.lo \ + sql_string.lo sql_table.lo sql_test.lo sql_udf.lo \ + sql_update.lo sql_yacc.lo table.lo thr_malloc.lo time.lo \ + unireg.lo uniques.lo stacktrace.lo sql_union.lo hash_filo.lo + +EXTRA_DIST = lib_vio.c + +# automake misses these +sql_yacc.cc sql_yacc.h: $(top_srcdir)/sql/sql_yacc.yy + +libmysqld_la_LIBADD = $(sqlobjects) $(libmysqlobjects) +## XXX: any time the client interface changes, we'll need to bump +## the version info for libmysqld; however, it's possible for the +## libmysqld interface to change without affecting the standard +## libmysqlclient interface. Should we make a separate version +## string for the two? +libmysqld_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@ +CLEANFILES = $(libmysqld_la_LIBADD) libmysqld.la + +# This is called from the toplevel makefile +link_sources: + set -x; \ + for f in $(sqlsources); do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \ + done; \ + for f in $(libmysqlsources); do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(srcdir)/../libmysql/$$f $(srcdir)/$$f; \ + done + +clean-local: + rm -f `echo $(sqlsources) $(libmysqlsources) | sed "s;\.lo;.c;g"` \ + $(top_srcdir)/linked_libmysqld_sources + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/libmysqld/WHITEPAPER b/libmysqld/WHITEPAPER new file mode 100644 index 00000000000..191cdb4e0fd --- /dev/null +++ b/libmysqld/WHITEPAPER @@ -0,0 +1,16 @@ +LIBRARY VERSION DESIGN (EMBEDDED SERVER) + + +- The library version of MySQL server is the client library that contains embedded server. + +- This client DLL has name : libmysqlclient_e (.la) + +- The client application that supposed to use MySQL LV need to be rebuilt against libmysqlclient_e.la. The rebuild process is necessary, because libmysqlclient_e is a LIBTOOL object, which has the different LIBS list compared to the original libmysqlclient.la. + +- The client and the server code run in the same process and the same thread; + +- The server code is invoked when client writes the command to the net, and when connection is established; + + + + diff --git a/libmysqld/copyright b/libmysqld/copyright new file mode 100644 index 00000000000..0b4dd1725a2 --- /dev/null +++ b/libmysqld/copyright @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2000 + * SWsoft company + * + * This material is provided "as is", with absolutely no warranty expressed + * or implied. Any use is at your own risk. + * + * Permission to use or copy this software for any purpose is hereby granted + * without fee, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + * + */ diff --git a/libmysqld/lib_load.cc b/libmysqld/lib_load.cc new file mode 100644 index 00000000000..37bd611b483 --- /dev/null +++ b/libmysqld/lib_load.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 + * SWsoft company + * + * This material is provided "as is", with absolutely no warranty expressed + * or implied. Any use is at your own risk. + * + * Permission to use or copy this software for any purpose is hereby granted + * without fee, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + * + */ +/* Copy data from a textfile to table */ + +#include "mysql_priv.h" +#include <my_dir.h> +#include <m_ctype.h> + + +int +mysql_load_internal(THD * thd, sql_exchange * ex, TABLE_LIST * table_list, + List<Item> & fields, enum enum_duplicates handle_duplicates, + bool read_file_from_client, thr_lock_type lock_type); + +int +mysql_load(THD * thd, sql_exchange * ex, TABLE_LIST * table_list, + List<Item> & fields, enum enum_duplicates handle_duplicates, + bool read_file_from_client, thr_lock_type lock_type) +{ + read_file_from_client = 0; //server is always in the same process + return mysql_load_internal(thd, ex, table_list, fields, handle_duplicates, + read_file_from_client, lock_type); +} + +#define mysql_load mysql_load_internal + +#include "../sql/sql_load.cc" diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc new file mode 100644 index 00000000000..739f1fc7fe7 --- /dev/null +++ b/libmysqld/lib_sql.cc @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2000 + * SWsoft company + * + * This material is provided "as is", with absolutely no warranty expressed + * or implied. Any use is at your own risk. + * + * Permission to use or copy this software for any purpose is hereby granted + * without fee, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + * + */ +#include "global.h" +#include "my_pthread.h" +#include "sys/types.h" +#include "../regex/regex.h" +#include "my_sys.h" + +#define main main1 +#define mysql_unix_port mysql_inix_port1 +#define mysql_port mysql_port1 +#define net_read_timeout net_read_timeout1 +#define net_write_timeout net_write_timeout1 +#define changeable_vars changeable_vars1 +//#define mysql_tmpdir mysql_tmpdir1 + +extern "C" +{ +#include "mysql_com.h" +#include "lib_vio.c" +} + + +class THD; + +static int +check_connections1(THD * thd); + +static bool +check_user(THD *thd, enum_server_command command,const char *user, const char *passwd, const char *db, bool check_count); + +static int +check_connections2(THD * thd); + +extern void free_defaults(char ** argv); +void free_defaults_internal(char ** argv){if (argv) free_defaults(argv);} +#define free_defaults free_defaults_internal + +char mysql_data_home[FN_REFLEN]; +char * get_mysql_data_home(){return mysql_data_home;}; +#define mysql_data_home mysql_data_home_internal +#include "../sql/mysqld.cc" + +#define SCRAMBLE_LENGTH 8 +extern "C" { + +/* +void +free_defaults(char ** argv) {}; +void +load_defaults(const char *, const char **, int *, char ***) {}; +*/ + +char * +get_mysql_home(){ return mysql_home;}; +char * +get_mysql_real_data_home(){ return mysql_real_data_home;}; + + +bool lib_dispatch_command(enum enum_server_command command, NET *net, + const char *arg, ulong length) +{ + THD *thd=(THD *) net->vio->dest_thd; + thd->store_globals(); // Fix if more than one connect + thd->net.last_error[0]=0; // Clear error message + thd->net.last_errno=0; + + net_new_transaction(&thd->net); + return dispatch_command(command, thd, (char *) arg, length + 1); +} + + + +void +lib_connection_phase(NET * net, int phase) +{ + THD * thd; + thd = (THD *)(net->vio->dest_thd); + if (thd) + { + switch (phase) + { + case 2: + check_connections2(thd); + break; + } + } +} +} +void start_embedded_conn1(NET * net) +{ + THD * thd = new THD; + my_net_init(&thd->net,NULL); + /* if (protocol_version>9) */ + thd->net.return_errno=1; + thd->thread_id = thread_id++; + + Vio * v = net->vio; + if (!v) + { + v = vio_new(0,VIO_CLOSED,0); + net->vio = v; + } + if (v) + { + v -> dest_thd = thd; + /* v -> dest_net = &thd->net; XXX: Probably not needed? */ + } + thd->net.vio = v; + if (thd->store_globals()) + { + fprintf(stderr,"store_globals failed.\n"); + return; + } + + thd->mysys_var=my_thread_var; + thd->dbug_thread_id=my_thread_id(); + thd->thread_stack= (char*) &thd; + + if (thd->max_join_size == HA_POS_ERROR) + thd->options |= OPTION_BIG_SELECTS; + if (thd->options & OPTION_ANSI_MODE) + thd->client_capabilities|=CLIENT_IGNORE_SPACE; + + thd->proc_info=0; // Remove 'login' + thd->command=COM_SLEEP; + thd->version=refresh_version; + thd->set_time(); + init_sql_alloc(&thd->mem_root,8192,8192); + + check_connections1(thd); +} + + + + +static int +check_connections1(THD *thd) +{ + uint connect_errors=0; + NET *net= &thd->net; + /* + ** store the connection details + */ + DBUG_PRINT("info", (("check_connections called by thread %d"), + thd->thread_id)); + DBUG_PRINT("general",("New connection received on %s", + vio_description(net->vio))); + if (!thd->host) // If TCP/IP connection + { + thd->host=(char*) localhost; + } + else /* Hostname given means that the connection was on a socket */ + { + DBUG_PRINT("general",("Host: %s",thd->host)); + thd->ip=0; + bzero((char*) &thd->remote,sizeof(struct sockaddr)); + } + //vio_keepalive(net->vio, TRUE); + + /* nasty, but any other way? */ + uint pkt_len = 0; + + char buff[80],*end; + int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_TRANSACTIONS; + LINT_INIT(pkt_len); + + end=strmov(buff,server_version)+1; + int4store((uchar*) end,thd->thread_id); + end+=4; + memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1); + end+=SCRAMBLE_LENGTH +1; + int2store(end,client_flags); + end[2]=MY_CHARSET_CURRENT; + +#define MIN_HANDSHAKE_SIZE 6 + + int2store(end+3,thd->server_status); + bzero(end+5,13); + end+=18; + if (net_write_command(net,protocol_version, buff, + (uint) (end-buff))) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + return 0; +} + +static int +check_connections2(THD * thd) +{ +uint connect_errors=0; +uint pkt_len = 0; +NET * net = &thd -> net; +if (protocol_version>9) net -> return_errno=1; + + if ( (pkt_len=my_net_read(net)) == packet_error || + pkt_len < MIN_HANDSHAKE_SIZE) + { + inc_host_errors(&thd->remote.sin_addr); + return(ER_HANDSHAKE_ERROR); + } + +#ifdef _CUSTOMCONFIG_ +#include "_cust_sql_parse.h" +#endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); + if (thd->packet.alloc(net_buffer_length)) + return(ER_OUT_OF_RESOURCES); + + thd->client_capabilities=uint2korr(net->read_pos); + + thd->max_packet_length=uint3korr(net->read_pos+2); + char *user= (char*) net->read_pos+5; + char *passwd= strend(user)+1; + char *db=0; + if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH) + return ER_HANDSHAKE_ERROR; + if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) + db=strend(passwd)+1; + if (thd->client_capabilities & CLIENT_INTERACTIVE) + thd->inactive_timeout=net_interactive_timeout; + if (thd->client_capabilities & CLIENT_TRANSACTIONS) + thd->net.return_status= &thd->server_status; + net->timeout=net_read_timeout; + if (check_user(thd,COM_CONNECT, user, passwd, db, 1)) + return (-1); + thd->password=test(passwd[0]); + return 0; +} + + + + + + + + + + + +static bool check_user(THD *thd,enum_server_command command, const char *user, + const char *passwd, const char *db, bool check_count) +{ + NET *net= &thd->net; + thd->db=0; + + if (!(thd->user = my_strdup(user, MYF(0)))) + { + send_error(net,ER_OUT_OF_RESOURCES); + return 1; + } + thd->master_access=acl_getroot(thd->host, thd->ip, thd->user, + passwd, thd->scramble, &thd->priv_user, + protocol_version == 9 || + !(thd->client_capabilities & + CLIENT_LONG_PASSWORD)); + DBUG_PRINT("general", + ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", + thd->client_capabilities, thd->max_packet_length, + thd->host ? thd->host : thd->ip, thd->priv_user, + passwd[0] ? "yes": "no", + thd->master_access, thd->db ? thd->db : "*none*")); + if (thd->master_access & NO_ACCESS) + { + net_printf(net, ER_ACCESS_DENIED_ERROR, + thd->user, + thd->host ? thd->host : thd->ip, + passwd[0] ? ER(ER_YES) : ER(ER_NO)); + mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), + thd->user, + thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", + passwd[0] ? ER(ER_YES) : ER(ER_NO)); + return(1); // Error already given + } + if (check_count) + { + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool tmp=(thread_count - delayed_insert_threads >= max_connections && + !(thd->master_access & PROCESS_ACL)); + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (tmp) + { // Too many connections + send_error(net, ER_CON_COUNT_ERROR); + return(1); + } + } + mysql_log.write(thd,command, + (thd->priv_user == thd->user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + user, + thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", + db ? db : (char*) ""); + thd->db_access=0; + if (db && db[0]) + return test(mysql_change_db(thd,db)); + else + send_ok(net); // Ready to handle questions + return 0; // ok +} + + +extern "C"{ +void mysql_server_init(int argc, char **argv, const char **groups) +{ + char hostname[FN_REFLEN]; + + /* This mess is to allow people to call the init function without + * having to mess with a fake argv */ + int *argcp; + char ***argvp; + int fake_argc = 1; + char *fake_argv[] = { (char *)"", 0 }; + const char *fake_groups[] = { "server", 0 }; + if (argc) + { + argcp = &argc; + argvp = &argv; + } + else + { + argcp = &fake_argc; + argvp = (char ***)&fake_argv; + } + if (!groups) + groups = fake_groups; + + my_umask=0660; // Default umask for new files + my_umask_dir=0700; // Default umask for new directories + MY_INIT((char *)"mysqld"); // init my_sys library & pthreads + tzset(); // Set tzname + + start_time=time((time_t*) 0); +#ifdef HAVE_TZNAME +#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) + { + struct tm tm_tmp; + localtime_r(&start_time,&tm_tmp); + strmov(time_zone,tzname[tm_tmp.tm_isdst == 1 ? 1 : 0]); + } +#else + { + struct tm *start_tm; + start_tm=localtime(&start_time); + strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]); + } +#endif +#endif + + if (gethostname(hostname,sizeof(hostname)-4) < 0) + strmov(hostname,"mysql"); + strmov(pidfile_name,hostname); + strmov(strcend(pidfile_name,'.'),".pid"); // Add extension +#ifdef DEMO_VERSION + strcat(server_version,"-demo"); +#endif +#ifdef SHAREWARE_VERSION + strcat(server_version,"-shareware"); +#endif +#ifndef DBUG_OFF + strcat(server_version,"-debug"); +#endif + strcat(server_version,"-library-ver"); +#ifdef _CUSTOMSTARTUPCONFIG_ + if (_cust_check_startup()) + { + /* _cust_check_startup will report startup failure error */ + exit( 1 ); + } +#endif + load_defaults("my", groups, argcp, argvp); + defaults_argv=*argvp; + mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ +#ifdef __WIN__ + if (!mysql_tmpdir) + mysql_tmpdir=getenv("TEMP"); + if (!mysql_tmpdir) + mysql_tmpdir=getenv("TMP"); +#endif + if (!mysql_tmpdir || !mysql_tmpdir[0]) + mysql_tmpdir=strdup((char*) P_tmpdir); + set_options(); + get_options(*argcp, *argvp); + + if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) + strcat(server_version,"-log"); + DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, + server_version, SYSTEM_TYPE,MACHINE_TYPE)); + + /* These must be set early */ + + (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW); + (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_binlog_update, MY_MUTEX_INIT_FAST); // QQ NOT USED + (void) pthread_mutex_init(&LOCK_slave, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_server_id, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); + (void) pthread_cond_init(&COND_thread_count,NULL); + (void) pthread_cond_init(&COND_refresh,NULL); + (void) pthread_cond_init(&COND_thread_cache,NULL); + (void) pthread_cond_init(&COND_flush_thread_cache,NULL); + (void) pthread_cond_init(&COND_manager,NULL); + (void) pthread_cond_init(&COND_binlog_update, NULL); + (void) pthread_cond_init(&COND_slave_stopped, NULL); + (void) pthread_cond_init(&COND_slave_start, NULL); + + if (set_default_charset_by_name(default_charset, MYF(MY_WME))) + unireg_abort(1); + charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS)); + + + if (!(opt_specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),CONNECT_PRIOR); + /* Parameter for threads created for connections */ + (void) pthread_attr_init(&connection_attrib); + (void) pthread_attr_setdetachstate(&connection_attrib, + PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&connection_attrib,thread_stack); + + if (!(opt_specialflag & SPECIAL_NO_PRIOR)) + my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR); + pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM); + +#ifdef SET_RLIMIT_NOFILE + /* connections and databases neads lots of files */ + { + uint wanted_files=10+(uint) max(max_connections*5, + max_connections+table_cache_size*2); + uint files=set_maximum_open_files(wanted_files); + if (files && files < wanted_files) // Some systems return 0 + { + max_connections= (ulong) min((files-10),max_connections); + table_cache_size= (ulong) max((files-10-max_connections)/2,64); + DBUG_PRINT("warning", + ("Changed limits: max_connections: %ld table_cache: %ld", + max_connections,table_cache_size)); + sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size); + } + } +#endif + unireg_init(opt_specialflag); /* Set up extern variabels */ + init_errmessage(); /* Read error messages from file */ + lex_init(); + item_init(); + mysys_uses_curses=0; +#ifdef USE_REGEX + regex_init(); +#endif + select_thread=pthread_self(); + select_thread_in_use=1; + + /* + ** We have enough space for fiddling with the argv, continue + */ + umask(((~my_umask) & 0666)); +// strcpy(mysql_real_data_home, "/usr/local"); + //if (my_setwd(mysql_real_data_home,MYF(MY_WME))) + //{ + // unireg_abort(1); /* purecov: inspected */ + //} + //mysql_data_home[0]=FN_CURLIB; // all paths are relative from here + //mysql_data_home[1]=0; + + strcpy(get_mysql_data_home(), mysql_real_data_home); + + //server_init(); + table_cache_init(); + hostname_cache_init(); + sql_cache_init(); + randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); + reset_floating_point_exceptions(); + init_thr_lock(); + + /* Setup log files */ + if (opt_log) + open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL); + if (opt_update_log) + open_log(&mysql_update_log, hostname, opt_update_logname, "", + LOG_NEW); + if (opt_bin_log) + { + if(server_id) + { + if (!opt_bin_logname) + { + char tmp[FN_REFLEN]; + strnmov(tmp,hostname,FN_REFLEN-5); + strmov(strcend(tmp,'.'),"-bin"); + opt_bin_logname=my_strdup(tmp,MYF(MY_WME)); + } + mysql_bin_log.set_index_file_name(opt_binlog_index_name); + open_log(&mysql_bin_log, hostname, opt_bin_logname, "-bin", + LOG_BIN); + } + else + sql_print_error("Server id is not set - binary logging disabled"); + } + + if (opt_slow_log) + open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log", + LOG_NORMAL); + if (ha_init()) + { + sql_print_error("Can't init databases"); + exit(1); + } +#ifdef HAVE_MLOCKALL + if (locked_in_memory && !geteuid()) + { + ha_key_cache(); + if (mlockall(MCL_CURRENT)) + { + sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno); + } + else + locked_in_memory=1; + } +#else + locked_in_memory=0; +#endif + + if (opt_myisam_log) + (void) mi_log( 1 ); + ft_init_stopwords(ft_precompiled_stopwords); /* SerG */ + + /* + init signals & alarm + After this we can't quit by a simple unireg_abort + */ + error_handler_hook = my_message_sql; + if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) || + pthread_key_create(&THR_MALLOC,NULL)) + { + sql_print_error("Can't create thread-keys"); + exit(1); + } + //init_signals(); + opt_noacl = 1; + if (acl_init(opt_noacl)) + { + select_thread_in_use=0; + (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL); + exit(1); + } + if (!opt_noacl) + (void) grant_init(); + +#ifdef HAVE_DLOPEN + if (!opt_noacl) + udf_init(); +#endif + + if (opt_bootstrap) + { + int error=bootstrap(stdin); + end_thr_alarm(); // Don't allow alarms + unireg_abort(error ? 1 : 0); + } + if (opt_init_file) + { + if (read_init_file(opt_init_file)) + { + end_thr_alarm(); // Don't allow alarms + unireg_abort(1); + } + } + (void) thr_setconcurrency(concurrency); // 10 by default + + if (flush_time && flush_time != ~(ulong) 0L) + { + pthread_t hThread; + if (pthread_create(&hThread,&connection_attrib,handle_manager,0)) + sql_print_error("Warning: Can't create thread to manage maintenance"); + } + + // slave thread + if(master_host) + { + if(server_id) + { + pthread_t hThread; + if(!opt_skip_slave_start && + pthread_create(&hThread, &connection_attrib, handle_slave, 0)) + sql_print_error("Warning: Can't create thread to handle slave"); + } + else + sql_print_error("Server id is not set, slave thread will not be started"); + } + + //printf(ER(ER_READY),my_progname,server_version,""); + //printf("%s initialized.\n", server_version); + fflush(stdout); +} + +void mysql_server_end() +{ + /* (void) pthread_attr_destroy(&connection_attrib); */ + + DBUG_PRINT("quit",("Exiting main thread")); + +#ifdef EXTRA_DEBUG + sql_print_error("Before Lock_thread_count"); +#endif + (void) pthread_mutex_lock(&LOCK_thread_count); + select_thread_in_use=0; // For close_connections + (void) pthread_cond_broadcast(&COND_thread_count); + (void) pthread_mutex_unlock(&LOCK_thread_count); +#ifdef EXTRA_DEBUG + sql_print_error("After lock_thread_count"); +#endif + +// /* Wait until cleanup is done */ +// (void) pthread_mutex_lock(&LOCK_thread_count); +// while (!ready_to_exit) +// { +// pthread_cond_wait(&COND_thread_count,&LOCK_thread_count); +// } +// (void) pthread_mutex_unlock(&LOCK_thread_count); + unireg_end(0); + my_thread_end(); +} + +my_bool mysql_thread_init() +{ +#ifdef THREAD + return my_thread_init(); +#else + return 0; +#endif +} + +void mysql_thread_end() +{ +#ifdef THREAD + my_thread_end(); +#endif +} + +void start_embedded_connection(NET * net) +{ + start_embedded_conn1(net); +} +//==================================================================== +} +int embedded_do_command(NET * net) +{ + THD * thd = (THD *) net ->vio; + do_command(thd); + return 0; +} + + + diff --git a/libmysqld/lib_vio.c b/libmysqld/lib_vio.c new file mode 100644 index 00000000000..fd4eb4ac29f --- /dev/null +++ b/libmysqld/lib_vio.c @@ -0,0 +1,243 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + +/* + Note that we can't have assertion on file descriptors; The reason for + this is that during mysql shutdown, another thread can close a file + we are working on. In this case we should just return read errors from + the file descriptior. +*/ + +#include <global.h> + +#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */ + +#include <errno.h> +#include <my_sys.h> +#include "mysql.h" +#include <violite.h> +#include <my_sys.h> +#include <my_net.h> +#include <m_string.h> +#include <dbug.h> +#include <assert.h> + +#if defined(__EMX__) +#include <sys/ioctl.h> +#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C))) +#undef HAVE_FCNTL +#endif /* defined(__EMX__) */ + +#if defined(MSDOS) || defined(__WIN__) +#ifdef __WIN__ +#undef errno +#undef EINTR +#undef EAGAIN +#define errno WSAGetLastError() +#define EINTR WSAEINTR +#define EAGAIN WSAEINPROGRESS +#endif /* __WIN__ */ +#define O_NONBLOCK 1 /* For emulation of fcntl() */ +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +#ifndef __WIN__ +#define HANDLE void * +#endif + +struct st_vio +{ + my_socket sd; /* my_socket - real or imaginary */ + HANDLE hPipe; + my_bool localhost; /* Are we from localhost? */ + int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ + struct sockaddr_in local; /* Local internet address */ + struct sockaddr_in remote; /* Remote internet address */ + enum enum_vio_type type; /* Type of connection */ + char desc[30]; /* String description */ + /* #ifdef EMBEDDED_LIBRARY */ + /* void *dest_net; */ + void *dest_thd; + char *packets, **last_packet; + char *where_in_packet, *end_of_packet; + my_bool reading; + MEM_ROOT root; + /* #endif */ +}; + +/* Initialize the communication buffer */ + +Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) +{ + Vio * vio = NULL; + vio = (Vio *) my_malloc (sizeof(*vio),MYF(MY_WME|MY_ZEROFILL)); + if (vio) + { + init_alloc_root(&vio->root, 8192, 1024); + vio->root.min_malloc = sizeof(char *) + 4; + vio->last_packet = &vio->packets; + } + return (vio); +} + + +#ifdef __WIN__ + +Vio *vio_new_win32pipe(HANDLE hPipe) +{ + return (NULL); +} + +#endif + +void vio_delete(Vio * vio) +{ + if (vio) + { + if (vio->type != VIO_CLOSED) vio_close(vio); + free_root(&vio->root, MYF(0)); + my_free((gptr)vio, MYF(0)); + } +} + +void vio_reset(Vio *vio) +{ + free_root(&vio->root, MYF(MY_KEEP_PREALLOC)); + vio->packets = vio->where_in_packet = vio->end_of_packet = 0; + vio->last_packet = &vio->packets; +} + +int vio_errno(Vio *vio __attribute__((unused))) +{ + return errno; /* On Win32 this mapped to WSAGetLastError() */ +} + +int vio_read(Vio * vio, gptr buf, int size) +{ + vio->reading = 1; + if (vio->where_in_packet >= vio->end_of_packet) + { + dbug_assert(vio->packets); + vio->where_in_packet = vio->packets + sizeof(char *) + 4; + vio->end_of_packet = vio->where_in_packet + + uint4korr(vio->packets + sizeof(char *)); + vio->packets = *(char **)vio->packets; + } + if (vio->where_in_packet + size > vio->end_of_packet) + size = vio->end_of_packet - vio->where_in_packet; + memcpy(buf, vio->where_in_packet, size); + vio->where_in_packet += size; + return (size); +} + +int vio_write(Vio * vio, const gptr buf, int size) +{ + char *packet; + if (vio->reading) + { + vio->reading = 0; + vio_reset(vio); + } + if ((packet = alloc_root(&vio->root, sizeof(char*) + 4 + size))) + { + *vio->last_packet = packet; + vio->last_packet = (char **)packet; + *((char **)packet) = 0; /* Set forward link to 0 */ + packet += sizeof(char *); + int4store(packet, size); + memcpy(packet + 4, buf, size); + } + else + size= -1; + return (size); +} + +int vio_blocking(Vio * vio, my_bool set_blocking_mode) +{ + int r=0; + return (r); +} + +my_bool +vio_is_blocking(Vio * vio) +{ + my_bool r=0; + return(r); +} + +int vio_fastsend(Vio * vio) +{ + int r=0; + return(r); +} + +int vio_keepalive(Vio* vio, my_bool set_keep_alive) +{ + int r=0; + return (r); +} + + +my_bool +vio_should_retry(Vio * vio __attribute__((unused))) +{ + int en = errno; + return en == EAGAIN || en == EINTR || en == EWOULDBLOCK; +} + + +int vio_close(Vio * vio) +{ + int r=0; + return(r); +} + + +const char *vio_description(Vio * vio) +{ + return "embedded vio"; +} + +enum enum_vio_type vio_type(Vio* vio) +{ + return VIO_CLOSED; +} + +my_socket vio_fd(Vio* vio) +{ + return 0; +} + + +my_bool vio_peer_addr(Vio * vio, char *buf) +{ + return(0); +} + + +void vio_in_addr(Vio *vio, struct in_addr *in) +{ +} + +my_bool vio_poll_read(Vio *vio,uint timeout) +{ + return 0; +} + +#endif /* HAVE_VIO */ diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c new file mode 100644 index 00000000000..0e66ceb2f40 --- /dev/null +++ b/libmysqld/libmysqld.c @@ -0,0 +1,2063 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + +#define DONT_USE_RAID +#include <global.h> +#if defined(__WIN__) || defined(_WIN32) || defined(_WIN64) +#include <winsock.h> +#include <odbcinst.h> +#endif +#include <my_sys.h> +#include <mysys_err.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" +#include "mysql_version.h" +#include "mysqld_error.h" +#include "errmsg.h" +#include <violite.h> +#include <sys/stat.h> +#include <signal.h> +#include <time.h> +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#if !defined(MSDOS) && !defined(__WIN__) +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#ifdef HAVE_SELECT_H +# include <select.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#endif +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#endif +#if defined(THREAD) && !defined(__WIN__) +#include <my_pthread.h> /* because of signal() */ +#endif +#ifndef INADDR_NONE +#define INADDR_NONE -1 +#endif + +static my_bool mysql_client_init=0; +uint mysql_port=0; +my_string mysql_unix_port=0; + +#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS) + +#if defined(MSDOS) || defined(__WIN__) +#define ERRNO WSAGetLastError() +#define perror(A) +#else +#include <errno.h> +#define ERRNO errno +#define SOCKET_ERROR -1 +#define closesocket(A) close(A) +#endif + +/* XXX: this is real ugly... */ +extern void start_embedded_connection(NET * net); +extern void lib_connection_phase(NET *net, int phase); +extern bool lib_dispatch_command(enum enum_server_command command, NET *net, + const char *arg, ulong length); + +static void mysql_once_init(void); +static MYSQL_DATA *read_rows (MYSQL *mysql,MYSQL_FIELD *fields, + uint field_count); +static int read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, + ulong *lengths); +static void end_server(MYSQL *mysql); +static void read_user_name(char *name); +static void append_wild(char *to,char *end,const char *wild); +static my_bool mysql_reconnect(MYSQL *mysql); +static int send_file_to_server(MYSQL *mysql,const char *filename); +static sig_handler pipe_sig_handler(int sig); +static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, + const char *from, ulong length); + +#define init_sigpipe_variables +#define set_sigpipe(mysql) +#define reset_sigpipe(mysql) + +/***************************************************************************** +** read a packet from server. Give error message if socket was down +** or packet is an error message +*****************************************************************************/ + +static uint +net_safe_read(MYSQL *mysql) +{ + NET *net= &mysql->net; + uint len=0; + //init_sigpipe_variables + /* Don't give sigpipe errors if the client doesn't want them */ + set_sigpipe(mysql); + if (net->vio != 0) + len=my_net_read(net); + reset_sigpipe(mysql); + if (len == packet_error || len == 0) + { + DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", + vio_description(net->vio),len)); + end_server(mysql); + net->last_errno=(net->last_errno == ER_NET_PACKET_TOO_LARGE ? + CR_NET_PACKET_TOO_LARGE: + CR_SERVER_LOST); + strmov(net->last_error,ER(net->last_errno)); + return(packet_error); + } + if (net->read_pos[0] == 255) + { + + if (len > 3) + { + char *pos=(char*) net->read_pos+1; + if (mysql->protocol_version > 9) + { /* New client protocol */ + net->last_errno=uint2korr(pos); + pos+=2; + len-=2; + } + else + { + net->last_errno=CR_UNKNOWN_ERROR; + len--; + } + (void) strmake(net->last_error,(char*) pos, + min(len,sizeof(net->last_error)-1)); + } + else + { + net->last_errno=CR_UNKNOWN_ERROR; + (void) strmov(net->last_error,ER(net->last_errno)); + } + DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno, + net->last_error)); + return(packet_error); + } + return len; +} + + +/* Get the length of next field. Change parameter to point at fieldstart */ +static ulong +net_field_length(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (ulong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (ulong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (ulong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ + return (ulong) uint4korr(pos+1); +} + +/* Same as above, but returns ulonglong values */ + +static my_ulonglong +net_field_length_ll(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (my_ulonglong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return (my_ulonglong) NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (my_ulonglong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (my_ulonglong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ +#ifdef NO_CLIENT_LONGLONG + return (my_ulonglong) uint4korr(pos+1); +#else + return (my_ulonglong) uint8korr(pos+1); +#endif +} + + +static void free_rows(MYSQL_DATA *cur) +{ + if (cur) + { + free_root(&cur->alloc,MYF(0)); + my_free((gptr) cur,MYF(0)); + } +} + + +static int +simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, + uint length, my_bool skipp_check) +{ + NET *net= &mysql->net; + int result= -1; + + /* Check that we are calling the client functions in right order */ + if (mysql->status != MYSQL_STATUS_READY) + { + strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + goto end; + } + + /* Clear result variables */ + mysql->net.last_error[0]=0; + mysql->net.last_errno=0; + mysql->info=0; + mysql->affected_rows= ~(my_ulonglong) 0; + + /* Clear receive buffer and vio packet list */ + net_clear(net); + vio_reset(net->vio); + + result = lib_dispatch_command(command, net, arg,length); + if (!skipp_check) + result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ? + -1 : 0); + end: + return result; +} + + +static void free_old_query(MYSQL *mysql) +{ + DBUG_ENTER("free_old_query"); + if (mysql->fields) + free_root(&mysql->field_alloc,MYF(0)); + init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */ + mysql->fields=0; + mysql->field_count=0; /* For API */ + DBUG_VOID_RETURN; +} + +#ifdef HAVE_GETPWUID +struct passwd *getpwuid(uid_t); +char* getlogin(void); +#endif + +#if !defined(MSDOS) && ! defined(VMS) && !defined(__WIN__) +static void read_user_name(char *name) +{ + DBUG_ENTER("read_user_name"); + if (geteuid() == 0) + (void) strmov(name,"root"); /* allow use of surun */ + else + { +#ifdef HAVE_GETPWUID + struct passwd *skr; + const char *str; +/*#ifdef __cplusplus + extern "C" struct passwd *getpwuid(uid_t); + extern "C" { char* getlogin(void); } +#else + char * getlogin(); + struct passwd *getpwuid(uid_t); +#endif +*/ + if ((str=getlogin()) == NULL) + { + if ((skr=getpwuid(geteuid())) != NULL) + str=skr->pw_name; + else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) && + !(str=getenv("LOGIN"))) + str="UNKNOWN_USER"; + } + (void) strmake(name,str,USERNAME_LENGTH); +#elif HAVE_CUSERID + (void) cuserid(name); +#else + strmov(name,"UNKNOWN_USER"); +#endif + } + DBUG_VOID_RETURN; +} + +#else /* If MSDOS || VMS */ + +static void read_user_name(char *name) +{ + char *str=getenv("USER"); + strmov(name,str ? str : "ODBC"); /* ODBC will send user variable */ +} + +#endif + +#ifdef __WIN__ +static my_bool is_NT(void) +{ + char *os=getenv("OS"); + return (os && !strcmp(os, "Windows_NT")) ? 1 : 0; +} +#endif + +/* +** Expand wildcard to a sql string +*/ + +static void +append_wild(char *to, char *end, const char *wild) +{ + end-=5; /* Some extra */ + if (wild && wild[0]) + { + to=strmov(to," like '"); + while (*wild && to < end) + { + if (*wild == '\\' || *wild == '\'') + *to++='\\'; + *to++= *wild++; + } + if (*wild) /* Too small buffer */ + *to++='%'; /* Nicer this way */ + to[0]='\''; + to[1]=0; + } +} + + + +/************************************************************************** +** Init debugging if MYSQL_DEBUG environment variable is found +**************************************************************************/ + +void STDCALL +mysql_debug(const char *debug) +{ +#ifndef DBUG_OFF + char *env; + if (_db_on_) + return; /* Already using debugging */ + if (debug) + { + DEBUGGER_ON; + DBUG_PUSH(debug); + } + else if ((env = getenv("MYSQL_DEBUG"))) + { + DEBUGGER_ON; + DBUG_PUSH(env); +#if !defined(_WINVER) && !defined(WINVER) + puts("\n-------------------------------------------------------"); + puts("MYSQL_DEBUG found. libmysql started with the following:"); + puts(env); + puts("-------------------------------------------------------\n"); +#else + { + char buff[80]; + strmov(strmov(buff,"libmysql: "),env); + MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK); + } +#endif + } +#endif +} + + +/************************************************************************** +** Close the server connection if we get a SIGPIPE + ARGSUSED +**************************************************************************/ + +static sig_handler +pipe_sig_handler(int sig __attribute__((unused))) +{ + DBUG_PRINT("info",("Hit by signal %d",sig)); +#ifdef DONT_REMEMBER_SIGNAL + (void) signal(SIGPIPE,pipe_sig_handler); +#endif +} + + +/************************************************************************** +** Shut down connection +**************************************************************************/ + +static void +end_server(MYSQL *mysql) +{ + DBUG_ENTER("end_server"); + if (mysql->net.vio != 0) + { + init_sigpipe_variables + DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); + set_sigpipe(mysql); + vio_delete(mysql->net.vio); + reset_sigpipe(mysql); + mysql->net.vio= 0; /* Marker */ + } + net_end(&mysql->net); + free_old_query(mysql); + DBUG_VOID_RETURN; +} + + +void STDCALL +mysql_free_result(MYSQL_RES *result) +{ + DBUG_ENTER("mysql_free_result"); + DBUG_PRINT("enter",("mysql_res: %lx",result)); + if (result) + { + if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) + { + DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows")); + for (;;) + { + uint pkt_len; + if ((pkt_len=(uint) net_safe_read(result->handle)) == packet_error) + break; + if (pkt_len == 1 && result->handle->net.read_pos[0] == 254) + break; /* End of data */ + } + result->handle->status=MYSQL_STATUS_READY; + } + free_rows(result->data); + if (result->fields) + free_root(&result->field_alloc,MYF(0)); + if (result->row) + my_free((gptr) result->row,MYF(0)); + my_free((gptr) result,MYF(0)); + } + DBUG_VOID_RETURN; +} + + +/**************************************************************************** +** Get options from my.cnf +****************************************************************************/ + +static const char *default_options[]= +{"port","socket","compress","password","pipe", "timeout", "user", + "init-command", "host", "database", "debug", "return-found-rows", + "ssl_key" ,"ssl_cert" ,"ssl_ca" ,"ssl_capath", + "character-set-dir", "default-character-set", + NullS +}; + +static TYPELIB option_types={array_elements(default_options)-1, + "options",default_options}; + +static void mysql_read_default_options(struct st_mysql_options *options, + const char *filename,const char *group) +{ + int argc; + char *argv_buff[1],**argv; + const char *groups[3]; + DBUG_ENTER("mysql_read_default_options"); + DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL")); + + argc=1; argv=argv_buff; argv_buff[0]= (char*) "client"; + groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0; + + load_defaults(filename, groups, &argc, &argv); + if (argc != 1) /* If some default option */ + { + char **option=argv; + while (*++option) + { + /* DBUG_PRINT("info",("option: %s",option[0])); */ + if (option[0][0] == '-' && option[0][1] == '-') + { + char *end=strcend(*option,'='); + char *opt_arg=0; + if (*end) + { + opt_arg=end+1; + *end=0; /* Remove '=' */ + } + switch (find_type(*option+2,&option_types,2)) { + case 1: /* port */ + if (opt_arg) + options->port=atoi(opt_arg); + break; + case 2: /* socket */ + if (opt_arg) + { + my_free(options->unix_socket,MYF(MY_ALLOW_ZERO_PTR)); + options->unix_socket=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 3: /* compress */ + options->compress=1; + break; + case 4: /* password */ + if (opt_arg) + { + my_free(options->password,MYF(MY_ALLOW_ZERO_PTR)); + options->password=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 5: /* pipe */ + options->named_pipe=1; /* Force named pipe */ + break; + case 6: /* timeout */ + if (opt_arg) + options->connect_timeout=atoi(opt_arg); + break; + case 7: /* user */ + if (opt_arg) + { + my_free(options->user,MYF(MY_ALLOW_ZERO_PTR)); + options->user=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 8: /* init-command */ + if (opt_arg) + { + my_free(options->init_command,MYF(MY_ALLOW_ZERO_PTR)); + options->init_command=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 9: /* host */ + if (opt_arg) + { + my_free(options->host,MYF(MY_ALLOW_ZERO_PTR)); + options->host=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 10: /* database */ + if (opt_arg) + { + my_free(options->db,MYF(MY_ALLOW_ZERO_PTR)); + options->db=my_strdup(opt_arg,MYF(MY_WME)); + } + break; + case 11: /* debug */ + mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace"); + break; + case 12: /* return-found-rows */ + options->client_flag|=CLIENT_FOUND_ROWS; + break; + case 13: /* Ignore SSL options */ + case 14: + case 15: + case 16: + break; + case 17: /* charset-lib */ + my_free(options->charset_dir,MYF(MY_ALLOW_ZERO_PTR)); + options->charset_dir = my_strdup(opt_arg, MYF(MY_WME)); + break; + case 18: + my_free(options->charset_name,MYF(MY_ALLOW_ZERO_PTR)); + options->charset_name = my_strdup(opt_arg, MYF(MY_WME)); + break; + default: + DBUG_PRINT("warning",("unknown option: %s",option[0])); + } + } + } + } + free_defaults(argv); + DBUG_VOID_RETURN; +} + + +/*************************************************************************** +** Change field rows to field structs +***************************************************************************/ + +static MYSQL_FIELD * +unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, my_bool long_flag_protocol) +{ + MYSQL_ROWS *row; + MYSQL_FIELD *field,*result; + DBUG_ENTER("unpack_fields"); + + field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields); + if (!result) + DBUG_RETURN(0); + + for (row=data->data; row ; row = row->next,field++) + { + field->table= strdup_root(alloc,(char*) row->data[0]); + field->name= strdup_root(alloc,(char*) row->data[1]); + field->length= (uint) uint3korr(row->data[2]); + field->type= (enum enum_field_types) (uchar) row->data[3][0]; + if (long_flag_protocol) + { + field->flags= uint2korr(row->data[4]); + field->decimals=(uint) (uchar) row->data[4][2]; + } + else + { + field->flags= (uint) (uchar) row->data[4][0]; + field->decimals=(uint) (uchar) row->data[4][1]; + } + if (INTERNAL_NUM_FIELD(field)) + field->flags|= NUM_FLAG; + if (default_value && row->data[5]) + field->def=strdup_root(alloc,(char*) row->data[5]); + else + field->def=0; + field->max_length= 0; + } + free_rows(data); /* Free old data */ + DBUG_RETURN(result); +} + + +/* Read all rows (fields or data) from server */ + +static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + uint fields) +{ + uint field,pkt_len; + ulong len; + uchar *cp; + char *to; + MYSQL_DATA *result; + MYSQL_ROWS **prev_ptr,*cur; + NET *net = &mysql->net; + DBUG_ENTER("read_rows"); + + if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error) + DBUG_RETURN(0); + if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), + MYF(MY_WME | MY_ZEROFILL)))) + { + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ + result->alloc.min_malloc=sizeof(MYSQL_ROWS); + prev_ptr= &result->data; + result->rows=0; + result->fields=fields; + + while (*(cp=net->read_pos) != 254 || pkt_len != 1) + { + result->rows++; + if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, + sizeof(MYSQL_ROWS))) || + !(cur->data= ((MYSQL_ROW) + alloc_root(&result->alloc, + (fields+1)*sizeof(char *)+pkt_len)))) + { + free_rows(result); + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + *prev_ptr=cur; + prev_ptr= &cur->next; + to= (char*) (cur->data+fields+1); + for (field=0 ; field < fields ; field++) + { + if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH) + { /* null field */ + cur->data[field] = 0; + } + else + { + cur->data[field] = to; + memcpy(to,(char*) cp,len); to[len]=0; + to+=len+1; + cp+=len; + if (mysql_fields) + { + if (mysql_fields[field].max_length < len) + mysql_fields[field].max_length=len; + } + } + } + cur->data[field]=to; /* End of last field */ + if ((pkt_len=net_safe_read(mysql)) == packet_error) + { + free_rows(result); + DBUG_RETURN(0); + } + } + *prev_ptr=0; /* last pointer is null */ + DBUG_PRINT("exit",("Got %d rows",result->rows)); + DBUG_RETURN(result); +} + + +/* +** Read one row. Uses packet buffer as storage for fields. +** When next packet is read, the previous field values are destroyed +*/ + + +static int +read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) +{ + uint field; + ulong pkt_len,len; + uchar *pos,*prev_pos; + + if ((pkt_len=(uint) net_safe_read(mysql)) == packet_error) + return -1; + if (pkt_len == 1 && mysql->net.read_pos[0] == 254) + return 1; /* End of data */ + prev_pos= 0; /* allowed to write at packet[-1] */ + pos=mysql->net.read_pos; + for (field=0 ; field < fields ; field++) + { + if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) + { /* null field */ + row[field] = 0; + *lengths++=0; + } + else + { + row[field] = (char*) pos; + pos+=len; + *lengths++=len; + } + if (prev_pos) + *prev_pos=0; /* Terminate prev field */ + prev_pos=pos; + } + row[field]=(char*) prev_pos+1; /* End of last field */ + *prev_pos=0; /* Terminate last field */ + return 0; +} + +/**************************************************************************** +** Init MySQL structure or allocate one +****************************************************************************/ + +MYSQL * STDCALL +mysql_init(MYSQL *mysql) +{ + mysql_once_init(); + if (!mysql) + { + if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) + return 0; + mysql->free_me=1; + mysql->net.vio = 0; + } + else + bzero((char*) (mysql),sizeof(*(mysql))); + return mysql; +} + + +static void mysql_once_init() +{ + if (!mysql_client_init) + { + mysql_client_init=1; + my_init(); /* Will init threads */ + init_client_errs(); + mysql_port = MYSQL_PORT; + mysql_debug(NullS); + } +#ifdef THREAD + else + my_thread_init(); /* Init if new thread */ +#endif +} + +/************************************************************************** +** Connect to sql server +** If host == 0 then use localhost +**************************************************************************/ + +MYSQL * STDCALL +mysql_connect(MYSQL *mysql,const char *host, + const char *user, const char *passwd) +{ + MYSQL *res; + mysql=mysql_init(mysql); /* Make it thread safe */ + { + DBUG_ENTER("mysql_connect"); + if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0))) + { + if (mysql->free_me) + my_free((gptr) mysql,MYF(0)); + } + DBUG_RETURN(res); + } +} + + +/* +** Note that the mysql argument must be initialized with mysql_init() +** before calling mysql_real_connect ! +*/ + +MYSQL * STDCALL +mysql_real_connect(MYSQL *mysql,const char *host, const char *user, + const char *passwd, const char *db, + uint port, const char *unix_socket,uint client_flag) +{ + char buff[100],charset_name_buff[16],*end,*host_info, *charset_name; + uint pkt_length; + NET *net= &mysql->net; + DBUG_ENTER("mysql_real_connect"); + DBUG_PRINT("enter",("host: %s db: %s user: %s", + host ? host : "(Null)", + db ? db : "(Null)", + user ? user : "(Null)")); + + net->vio = 0; /* If something goes wrong */ + /* use default options */ + if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) + { + mysql_read_default_options(&mysql->options, + (mysql->options.my_cnf_file ? + mysql->options.my_cnf_file : "my"), + mysql->options.my_cnf_group); + my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.my_cnf_file=mysql->options.my_cnf_group=0; + } + + /* Some empty-string-tests are done because of ODBC */ + if (!host || !host[0]) + host=mysql->options.host; + if (!user || !user[0]) + user=mysql->options.user; + if (!passwd) + { + passwd=mysql->options.password; + } + if (!db || !db[0]) + db=mysql->options.db; + port=0; + unix_socket=0; + mysql->reconnect=1; /* Reconnect as default */ + mysql->server_status=SERVER_STATUS_AUTOCOMMIT; + host_info=(char*) ER(CR_EMBEDDED_CONNECTION); + if (my_net_init(net, net->vio)) + { + vio_delete(net->vio); + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + goto error; + } + + /* Get version info */ + mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ + start_embedded_connection(net); + + if ((pkt_length=net_safe_read(mysql)) == packet_error) + goto error; + + /* Check if version of protocoll matches current one */ + + mysql->protocol_version= net->read_pos[0]; + DBUG_DUMP("packet",(char*) net->read_pos,10); + DBUG_PRINT("info",("mysql protocol version %d, server=%d", + PROTOCOL_VERSION, mysql->protocol_version)); + if (mysql->protocol_version != PROTOCOL_VERSION && + mysql->protocol_version != PROTOCOL_VERSION-1) + { + net->last_errno= CR_VERSION_ERROR; + sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version, + PROTOCOL_VERSION); + goto error; + } + end=strend((char*) net->read_pos+1); + mysql->thread_id=uint4korr(end+1); + end+=5; + strmake(mysql->scramble_buff,end,8); + end+=9; + if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) + mysql->server_capabilities=uint2korr(end); + if (pkt_length >= (uint) (end+18 - (char*) net->read_pos)) + { + /* New protocol with 16 bytes to describe server characteristics */ + mysql->server_language=end[2]; + mysql->server_status=uint2korr(end+3); + } + + /* Set character set */ + if ((charset_name=mysql->options.charset_name)) + { + const char *save=charsets_dir; + if (mysql->options.charset_dir) + charsets_dir=mysql->options.charset_dir; + mysql->charset=get_charset_by_name(mysql->options.charset_name, + MYF(MY_WME)); + charsets_dir=save; + } + else if (mysql->server_language) + { + charset_name=charset_name_buff; + sprintf(charset_name,"%d",mysql->server_language); /* In case of errors */ + mysql->charset=get_charset((uint8) mysql->server_language, MYF(MY_WME)); + } + else + mysql->charset=default_charset_info; + + if (!mysql->charset) + { + net->last_errno=CR_CANT_READ_CHARSET; + if (mysql->options.charset_dir) + sprintf(net->last_error,ER(net->last_errno), + charset_name ? charset_name : "unknown", + mysql->options.charset_dir); + else + { + char cs_dir_name[FN_REFLEN]; + get_charsets_dir(cs_dir_name); + sprintf(net->last_error,ER(net->last_errno), + charset_name ? charset_name : "unknown", + cs_dir_name); + } + goto error; + } + + /* Save connection information */ + if (!user) user=""; + if (!passwd) passwd=""; + host=LOCAL_HOST; + if (!my_multi_malloc(MYF(0), + &mysql->host_info, (uint) strlen(host_info)+1, + &mysql->host, (uint) strlen(host)+1, + &mysql->unix_socket,unix_socket ? + (uint) strlen(unix_socket)+1 : (uint) 1, + &mysql->server_version, + (uint) (end - (char*) net->read_pos), + NullS) || + !(mysql->user=my_strdup(user,MYF(0))) || + !(mysql->passwd=my_strdup(passwd,MYF(0)))) + { + strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY)); + goto error; + } + strmov(mysql->host_info,host_info); + strmov(mysql->host,host); + if (unix_socket) + strmov(mysql->unix_socket,unix_socket); + else + mysql->unix_socket=0; + strmov(mysql->server_version,(char*) net->read_pos+1); + mysql->port=port; + mysql->client_flag=client_flag | mysql->options.client_flag; + DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d", + mysql->server_version,mysql->server_capabilities, + mysql->server_status)); + + /* Send client information for access check */ + client_flag|=CLIENT_CAPABILITIES; + client_flag&= ~CLIENT_COMPRESS; + if (db) + client_flag|=CLIENT_CONNECT_WITH_DB; + int2store(buff,client_flag); + mysql->client_flag=client_flag; + + + int3store(buff+2,max_allowed_packet); + if (user && user[0]) + strmake(buff+5,user,32); + else + read_user_name((char*) buff+5); +#ifdef _CUSTOMCONFIG_ +#include "_cust_libmysql.h"; +#endif + DBUG_PRINT("info",("user: %s",buff+5)); + end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd, + (my_bool) (mysql->protocol_version == 9)); + + if (db) + { + end=strmov(end+1,db); + mysql->db=my_strdup(db,MYF(MY_WME)); + db=0; + } + if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net)) + goto error; + + lib_connection_phase(net,2); + + if( net_safe_read(mysql) == packet_error) + goto error; + if (db && mysql_select_db(mysql,db)) + goto error; + if (mysql->options.init_command) + { + my_bool reconnect=mysql->reconnect; + mysql->reconnect=0; + if (mysql_query(mysql,mysql->options.init_command)) + goto error; + mysql_free_result(mysql_use_result(mysql)); + mysql->reconnect=reconnect; + } + + DBUG_PRINT("exit",("Mysql handler: %lx",mysql)); + reset_sigpipe(mysql); + DBUG_RETURN(mysql); + +error: + reset_sigpipe(mysql); + DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error)); + { + /* Free alloced memory */ + my_bool free_me=mysql->free_me; + end_server(mysql); + mysql->free_me=0; + mysql_close(mysql); + mysql->free_me=free_me; + } + DBUG_RETURN(0); +} + + +static my_bool mysql_reconnect(MYSQL *mysql) +{ + MYSQL tmp_mysql; + DBUG_ENTER("mysql_reconnect"); + + if (!mysql->reconnect || + (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) + { + /* Allov reconnect next time */ + mysql->server_status&= ~SERVER_STATUS_IN_TRANS; + DBUG_RETURN(1); + } + mysql_init(&tmp_mysql); + tmp_mysql.options=mysql->options; + if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, + mysql->db, mysql->port, mysql->unix_socket, + mysql->client_flag)) + DBUG_RETURN(1); + tmp_mysql.free_me=mysql->free_me; + mysql->free_me=0; + bzero((char*) &mysql->options,sizeof(mysql->options)); + mysql_close(mysql); + *mysql=tmp_mysql; + net_clear(&mysql->net); + mysql->affected_rows= ~(my_ulonglong) 0; + DBUG_RETURN(0); +} + + +/************************************************************************** +** Change user and database +**************************************************************************/ + +my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, + const char *passwd, const char *db) +{ + char buff[512],*pos=buff; + DBUG_ENTER("mysql_change_user"); + + if (!user) + user=""; + if (!passwd) + passwd=""; + + pos=strmov(pos,user)+1; + pos=scramble(pos, mysql->scramble_buff, passwd, + (my_bool) (mysql->protocol_version == 9)); + pos=strmov(pos+1,db ? db : ""); + if (simple_command(mysql,COM_CHANGE_USER, buff,(uint) (pos-buff),0)) + DBUG_RETURN(1); + + my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + + mysql->user= my_strdup(user,MYF(MY_WME)); + mysql->passwd=my_strdup(passwd,MYF(MY_WME)); + mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0; + DBUG_RETURN(0); +} + + +/************************************************************************** +** Set current database +**************************************************************************/ + +int STDCALL +mysql_select_db(MYSQL *mysql, const char *db) +{ + int error; + DBUG_ENTER("mysql_select_db"); + DBUG_PRINT("enter",("db: '%s'",db)); + + if ((error=simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0))) + DBUG_RETURN(error); + my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + mysql->db=my_strdup(db,MYF(MY_WME)); + DBUG_RETURN(0); +} + + +/************************************************************************* +** Send a QUIT to the server and close the connection +** If handle is alloced by mysql connect free it. +*************************************************************************/ + +void STDCALL +mysql_close(MYSQL *mysql) +{ + DBUG_ENTER("mysql_close"); + if (mysql) /* Some simple safety */ + { + if (mysql->net.vio != 0) + { + free_old_query(mysql); + mysql->status=MYSQL_STATUS_READY; /* Force command */ + simple_command(mysql,COM_QUIT,"",0,1); + end_server(mysql); + } + my_free((gptr) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.user,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.host,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.password,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.unix_socket,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.db,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); + /* Clear pointers for better safety */ + mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; + bzero((char*) &mysql->options,sizeof(mysql->options)); + mysql->net.vio = 0; +#ifdef HAVE_OPENSSL + ((VioConnectorFd*)(mysql->connector_fd))->delete(); + mysql->connector_fd = 0; +#endif /* HAVE_OPENSSL */ + if (mysql->free_me) + my_free((gptr) mysql,MYF(0)); + } + DBUG_VOID_RETURN; +} + + +/************************************************************************** +** Do a query. If query returned rows, free old rows. +** Read data by mysql_store_result or by repeat call of mysql_fetch_row +**************************************************************************/ + +int STDCALL +mysql_query(MYSQL *mysql, const char *query) +{ + return mysql_real_query(mysql,query, (uint) strlen(query)); +} + +int STDCALL +mysql_send_query(MYSQL* mysql, const char* query, uint length) +{ + return simple_command(mysql, COM_QUERY, query, length, 1); +} + + +int STDCALL +mysql_read_query_result(MYSQL *mysql) +{ + uchar *pos; + ulong field_count; + MYSQL_DATA *fields; + uint length; + DBUG_ENTER("mysql_read_query_result"); + + if ((length=net_safe_read(mysql)) == packet_error) + DBUG_RETURN(-1); + free_old_query(mysql); /* Free old result */ +get_info: + pos=(uchar*) mysql->net.read_pos; + if ((field_count= net_field_length(&pos)) == 0) + { + mysql->affected_rows= net_field_length_ll(&pos); + mysql->insert_id= net_field_length_ll(&pos); + if (mysql->server_capabilities & CLIENT_TRANSACTIONS) + { + mysql->server_status=uint2korr(pos); pos+=2; + } + if (pos < mysql->net.read_pos+length && net_field_length(&pos)) + mysql->info=(char*) pos; + DBUG_RETURN(0); + } + if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ + { + int error=send_file_to_server(mysql,(char*) pos); + if ((length=net_safe_read(mysql)) == packet_error || error) + DBUG_RETURN(-1); + goto get_info; /* Get info packet */ + } + if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) + mysql->server_status|= SERVER_STATUS_IN_TRANS; + + mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ + if (!(fields=read_rows(mysql,(MYSQL_FIELD*) 0,5))) + DBUG_RETURN(-1); + if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, + (uint) field_count,0, + (my_bool) test(mysql->server_capabilities & + CLIENT_LONG_FLAG)))) + DBUG_RETURN(-1); + mysql->status=MYSQL_STATUS_GET_RESULT; + mysql->field_count=field_count; + DBUG_RETURN(0); +} + +int STDCALL +mysql_real_query(MYSQL *mysql, const char *query, uint length) +{ + DBUG_ENTER("mysql_real_query"); + DBUG_PRINT("enter",("handle: %lx",mysql)); + DBUG_PRINT("query",("Query = \"%s\"",query)); + if (mysql_send_query(mysql, query, length)) + DBUG_RETURN(-1); + DBUG_RETURN(mysql_read_query_result(mysql)); +} + + +static int +send_file_to_server(MYSQL *mysql, const char *filename) +{ + int fd, readcount; + char buf[IO_SIZE*15],*tmp_name; + DBUG_ENTER("send_file_to_server"); + + fn_format(buf,filename,"","",4); /* Convert to client format */ + if (!(tmp_name=my_strdup(buf,MYF(0)))) + { + strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY)); + DBUG_RETURN(-1); + } + if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0) + { + mysql->net.last_errno=EE_FILENOTFOUND; + sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno); + strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1); + my_net_write(&mysql->net,"",0); net_flush(&mysql->net); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + + while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0) + { + if (my_net_write(&mysql->net,buf,readcount)) + { + mysql->net.last_errno=CR_SERVER_LOST; + strmov(mysql->net.last_error,ER(mysql->net.last_errno)); + DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file")); + (void) my_close(fd,MYF(0)); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + } + (void) my_close(fd,MYF(0)); + /* Send empty packet to mark end of file */ + if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net)) + { + mysql->net.last_errno=CR_SERVER_LOST; + sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + if (readcount < 0) + { + mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */ + sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno); + strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + + +/************************************************************************** +** Alloc result struct for buffered results. All rows are read to buffer. +** mysql_data_seek may be used. +**************************************************************************/ + +MYSQL_RES * STDCALL +mysql_store_result(MYSQL *mysql) +{ + MYSQL_RES *result; + DBUG_ENTER("mysql_store_result"); + + if (!mysql->fields) + DBUG_RETURN(0); + if (mysql->status != MYSQL_STATUS_GET_RESULT) + { + strmov(mysql->net.last_error, + ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + DBUG_RETURN(0); + } + mysql->status=MYSQL_STATUS_READY; /* server is ready */ + if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+ + sizeof(ulong)*mysql->field_count, + MYF(MY_WME | MY_ZEROFILL)))) + { + mysql->net.last_errno=CR_OUT_OF_MEMORY; + strmov(mysql->net.last_error, ER(mysql->net.last_errno)); + DBUG_RETURN(0); + } + result->eof=1; /* Marker for buffered */ + result->lengths=(ulong*) (result+1); + if (!(result->data=read_rows(mysql,mysql->fields,mysql->field_count))) + { + my_free((gptr) result,MYF(0)); + DBUG_RETURN(0); + } + mysql->affected_rows= result->row_count= result->data->rows; + result->data_cursor= result->data->data; + result->fields= mysql->fields; + result->field_alloc= mysql->field_alloc; + result->field_count= mysql->field_count; + result->current_field=0; + result->current_row=0; /* Must do a fetch first */ + mysql->fields=0; /* fields is now in result */ + DBUG_RETURN(result); /* Data fetched */ +} + + +/************************************************************************** +** Alloc struct for use with unbuffered reads. Data is fetched by domand +** when calling to mysql_fetch_row. +** mysql_data_seek is a noop. +** +** No other queries may be specified with the same MYSQL handle. +** There shouldn't be much processing per row because mysql server shouldn't +** have to wait for the client (and will not wait more than 30 sec/packet). +**************************************************************************/ + +MYSQL_RES * STDCALL +mysql_use_result(MYSQL *mysql) +{ + MYSQL_RES *result; + DBUG_ENTER("mysql_use_result"); + + if (!mysql->fields) + DBUG_RETURN(0); + if (mysql->status != MYSQL_STATUS_GET_RESULT) + { + strmov(mysql->net.last_error, + ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + DBUG_RETURN(0); + } + if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+ + sizeof(ulong)*mysql->field_count, + MYF(MY_WME | MY_ZEROFILL)))) + DBUG_RETURN(0); + result->lengths=(ulong*) (result+1); + if (!(result->row=(MYSQL_ROW) + my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME)))) + { /* Ptrs: to one row */ + my_free((gptr) result,MYF(0)); + DBUG_RETURN(0); + } + result->fields= mysql->fields; + result->field_alloc= mysql->field_alloc; + result->field_count= mysql->field_count; + result->current_field=0; + result->handle= mysql; + result->current_row= 0; + mysql->fields=0; /* fields is now in result */ + mysql->status=MYSQL_STATUS_USE_RESULT; + DBUG_RETURN(result); /* Data is read to be fetched */ +} + + + +/************************************************************************** +** Return next field of the query results +**************************************************************************/ + +MYSQL_FIELD * STDCALL +mysql_fetch_field(MYSQL_RES *result) +{ + if (result->current_field >= result->field_count) + return(NULL); + return &result->fields[result->current_field++]; +} + + +/************************************************************************** +** Return next row of the query results +**************************************************************************/ + +MYSQL_ROW STDCALL +mysql_fetch_row(MYSQL_RES *res) +{ + DBUG_ENTER("mysql_fetch_row"); + if (!res->data) + { /* Unbufferred fetch */ + if (!res->eof) + { + if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths))) + { + res->row_count++; + DBUG_RETURN(res->current_row=res->row); + } + else + { + DBUG_PRINT("info",("end of data")); + res->eof=1; + res->handle->status=MYSQL_STATUS_READY; + } + } + DBUG_RETURN((MYSQL_ROW) NULL); + } + { + MYSQL_ROW tmp; + if (!res->data_cursor) + { + DBUG_PRINT("info",("end of data")); + DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL); + } + tmp = res->data_cursor->data; + res->data_cursor = res->data_cursor->next; + DBUG_RETURN(res->current_row=tmp); + } +} + +/************************************************************************** +** Get column lengths of the current row +** If one uses mysql_use_result, res->lengths contains the length information, +** else the lengths are calculated from the offset between pointers. +**************************************************************************/ + +ulong * STDCALL +mysql_fetch_lengths(MYSQL_RES *res) +{ + ulong *lengths,*prev_length; + byte *start; + MYSQL_ROW column,end; + + if (!(column=res->current_row)) + return 0; /* Something is wrong */ + if (res->data) + { + start=0; + prev_length=0; /* Keep gcc happy */ + lengths=res->lengths; + for (end=column+res->field_count+1 ; column != end ; column++,lengths++) + { + if (!*column) + { + *lengths=0; /* Null */ + continue; + } + if (start) /* Found end of prev string */ + *prev_length= (uint) (*column-start-1); + start= *column; + prev_length=lengths; + } + } + return res->lengths; +} + +/************************************************************************** +** Move to a specific row and column +**************************************************************************/ + +void STDCALL +mysql_data_seek(MYSQL_RES *result, my_ulonglong row) +{ + MYSQL_ROWS *tmp=0; + DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row)); + if (result->data) + for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ; + result->current_row=0; + result->data_cursor = tmp; +} + +/************************************************************************* +** put the row or field cursor one a position one got from mysql_row_tell() +** This doesn't restore any data. The next mysql_fetch_row or +** mysql_fetch_field will return the next row or field after the last used +*************************************************************************/ + +MYSQL_ROW_OFFSET STDCALL +mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row) +{ + MYSQL_ROW_OFFSET return_value=result->data_cursor; + result->current_row= 0; + result->data_cursor= row; + return return_value; +} + + +MYSQL_FIELD_OFFSET STDCALL +mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset) +{ + MYSQL_FIELD_OFFSET return_value=result->current_field; + result->current_field=field_offset; + return return_value; +} + +/***************************************************************************** +** List all databases +*****************************************************************************/ + +MYSQL_RES * STDCALL +mysql_list_dbs(MYSQL *mysql, const char *wild) +{ + char buff[255]; + DBUG_ENTER("mysql_list_dbs"); + + append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild); + if (mysql_query(mysql,buff)) + DBUG_RETURN(0); + DBUG_RETURN (mysql_store_result(mysql)); +} + + +/***************************************************************************** +** List all tables in a database +** If wild is given then only the tables matching wild is returned +*****************************************************************************/ + +MYSQL_RES * STDCALL +mysql_list_tables(MYSQL *mysql, const char *wild) +{ + char buff[255]; + DBUG_ENTER("mysql_list_tables"); + + append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild); + if (mysql_query(mysql,buff)) + DBUG_RETURN(0); + DBUG_RETURN (mysql_store_result(mysql)); +} + + +/************************************************************************** +** List all fields in a table +** If wild is given then only the fields matching wild is returned +** Instead of this use query: +** show fields in 'table' like "wild" +**************************************************************************/ + +MYSQL_RES * STDCALL +mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) +{ + MYSQL_RES *result; + MYSQL_DATA *query; + char buff[257],*end; + DBUG_ENTER("mysql_list_fields"); + DBUG_PRINT("enter",("table: '%s' wild: '%s'",table,wild ? wild : "")); + + LINT_INIT(query); + + end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128); + if (simple_command(mysql,COM_FIELD_LIST,buff,(uint) (end-buff),1) || + !(query = read_rows(mysql,(MYSQL_FIELD*) 0,6))) + DBUG_RETURN(NULL); + + free_old_query(mysql); + if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES), + MYF(MY_WME | MY_ZEROFILL)))) + { + free_rows(query); + DBUG_RETURN(NULL); + } + result->field_alloc=mysql->field_alloc; + mysql->fields=0; + result->field_count = (uint) query->rows; + result->fields= unpack_fields(query,&result->field_alloc, + result->field_count,1, + (my_bool) test(mysql->server_capabilities & + CLIENT_LONG_FLAG)); + result->eof=1; + DBUG_RETURN(result); +} + +/* List all running processes (threads) in server */ + +MYSQL_RES * STDCALL +mysql_list_processes(MYSQL *mysql) +{ + MYSQL_DATA *fields; + uint field_count; + uchar *pos; + DBUG_ENTER("mysql_list_processes"); + + LINT_INIT(fields); + if (simple_command(mysql,COM_PROCESS_INFO,"",0,0)) + DBUG_RETURN(0); + free_old_query(mysql); + pos=(uchar*) mysql->net.read_pos; + field_count=(uint) net_field_length(&pos); + if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0,5))) + DBUG_RETURN(NULL); + if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, + (my_bool) test(mysql->server_capabilities & + CLIENT_LONG_FLAG)))) + DBUG_RETURN(0); + mysql->status=MYSQL_STATUS_GET_RESULT; + mysql->field_count=field_count; + DBUG_RETURN(mysql_store_result(mysql)); +} + + +int STDCALL +mysql_create_db(MYSQL *mysql, const char *db) +{ + DBUG_ENTER("mysql_createdb"); + DBUG_PRINT("enter",("db: %s",db)); + DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (uint) strlen(db),0)); +} + + +int STDCALL +mysql_drop_db(MYSQL *mysql, const char *db) +{ + DBUG_ENTER("mysql_drop_db"); + DBUG_PRINT("enter",("db: %s",db)); + DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(uint) strlen(db),0)); +} + + +int STDCALL +mysql_shutdown(MYSQL *mysql) +{ + DBUG_ENTER("mysql_shutdown"); + DBUG_RETURN(simple_command(mysql,COM_SHUTDOWN,"",0,0)); +} + + +int STDCALL +mysql_refresh(MYSQL *mysql,uint options) +{ + uchar bits[1]; + DBUG_ENTER("mysql_refresh"); + bits[0]= (uchar) options; + DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0)); +} + +int STDCALL +mysql_kill(MYSQL *mysql,ulong pid) +{ + char buff[12]; + DBUG_ENTER("mysql_kill"); + int4store(buff,pid); + DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,4,0)); +} + + +int STDCALL +mysql_dump_debug_info(MYSQL *mysql) +{ + DBUG_ENTER("mysql_dump_debug_info"); + DBUG_RETURN(simple_command(mysql,COM_DEBUG,"",0,0)); +} + +char * STDCALL +mysql_stat(MYSQL *mysql) +{ + DBUG_ENTER("mysql_stat"); + if (simple_command(mysql,COM_STATISTICS,"",0,0)) + return mysql->net.last_error; + mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */ + if (!mysql->net.read_pos[0]) + { + mysql->net.last_errno=CR_WRONG_HOST_INFO; + strmov(mysql->net.last_error, ER(mysql->net.last_errno)); + return mysql->net.last_error; + } + DBUG_RETURN((char*) mysql->net.read_pos); +} + + +int STDCALL +mysql_ping(MYSQL *mysql) +{ + DBUG_ENTER("mysql_ping"); + DBUG_RETURN(simple_command(mysql,COM_PING,"",0,0)); +} + + +char * STDCALL +mysql_get_server_info(MYSQL *mysql) +{ + return((char*) mysql->server_version); +} + + +char * STDCALL +mysql_get_host_info(MYSQL *mysql) +{ + return(mysql->host_info); +} + + +uint STDCALL +mysql_get_proto_info(MYSQL *mysql) +{ + return (mysql->protocol_version); +} + +char * STDCALL +mysql_get_client_info(void) +{ + return (char*) MYSQL_SERVER_VERSION; +} + + +int STDCALL +mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg) +{ + DBUG_ENTER("mysql_option"); + DBUG_PRINT("enter",("option: %d",(int) option)); + switch (option) { + case MYSQL_OPT_CONNECT_TIMEOUT: + mysql->options.connect_timeout= *(uint*) arg; + break; + case MYSQL_OPT_COMPRESS: + mysql->options.compress=1; /* Remember for connect */ + break; + case MYSQL_OPT_NAMED_PIPE: + mysql->options.named_pipe=1; /* Force named pipe */ + break; + case MYSQL_INIT_COMMAND: + my_free(mysql->options.init_command,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.init_command=my_strdup(arg,MYF(MY_WME)); + break; + case MYSQL_READ_DEFAULT_FILE: + my_free(mysql->options.my_cnf_file,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME)); + break; + case MYSQL_READ_DEFAULT_GROUP: + my_free(mysql->options.my_cnf_group,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME)); + break; + case MYSQL_SET_CHARSET_DIR: + my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME)); + break; + case MYSQL_SET_CHARSET_NAME: + my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.charset_name=my_strdup(arg,MYF(MY_WME)); + break; + default: + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + +/**************************************************************************** +** Functions to get information from the MySQL structure +** These are functions to make shared libraries more usable. +****************************************************************************/ + +/* MYSQL_RES */ +my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res) +{ + return res->row_count; +} + +unsigned int STDCALL mysql_num_fields(MYSQL_RES *res) +{ + return res->field_count; +} + +my_bool STDCALL mysql_eof(MYSQL_RES *res) +{ + return res->eof; +} + +MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr) +{ + return &(res)->fields[fieldnr]; +} + +MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res) +{ + return (res)->fields; +} + +MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res) +{ + return res->data_cursor; +} + +uint STDCALL mysql_field_tell(MYSQL_RES *res) +{ + return (res)->current_field; +} + +/* MYSQL */ + +unsigned int STDCALL mysql_field_count(MYSQL *mysql) +{ + return mysql->field_count; +} + +my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) +{ + return (mysql)->affected_rows; +} + +my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql) +{ + return (mysql)->insert_id; +} + +uint STDCALL mysql_errno(MYSQL *mysql) +{ + return (mysql)->net.last_errno; +} + +char * STDCALL mysql_error(MYSQL *mysql) +{ + return (mysql)->net.last_error; +} + +char *STDCALL mysql_info(MYSQL *mysql) +{ + return (mysql)->info; +} + +ulong STDCALL mysql_thread_id(MYSQL *mysql) +{ + return (mysql)->thread_id; +} + +const char * STDCALL mysql_character_set_name(MYSQL *mysql) +{ + return mysql->charset->name; +} + + +uint STDCALL mysql_thread_safe(void) +{ +#ifdef THREAD + return 1; +#else + return 0; +#endif +} + +/**************************************************************************** +** Some support functions +****************************************************************************/ + +/* +** Add escape characters to a string (blob?) to make it suitable for a insert +** to should at least have place for length*2+1 chars +** Returns the length of the to string +*/ + +ulong STDCALL +mysql_escape_string(char *to,const char *from,ulong length) +{ + return mysql_sub_escape_string(default_charset_info,to,from,length); +} + +ulong STDCALL +mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, + ulong length) +{ + return mysql_sub_escape_string(mysql->charset,to,from,length); +} + + +static ulong +mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, + const char *from, ulong length) +{ + const char *to_start=to; + const char *end; +#ifdef USE_MB + my_bool use_mb_flag=use_mb(charset_info); +#endif + for (end=from+length; from != end ; from++) + { +#ifdef USE_MB + int l; + if (use_mb_flag && (l = my_ismbchar(charset_info, from, end))) + { + while (l--) + *to++ = *from++; + from--; + continue; + } +#endif + switch (*from) { + case 0: /* Must be escaped for 'mysql' */ + *to++= '\\'; + *to++= '0'; + break; + case '\n': /* Must be escaped for logs */ + *to++= '\\'; + *to++= 'n'; + break; + case '\r': + *to++= '\\'; + *to++= 'r'; + break; + case '\\': + *to++= '\\'; + *to++= '\\'; + break; + case '\'': + *to++= '\\'; + *to++= '\''; + break; + case '"': /* Better safe than sorry */ + *to++= '\\'; + *to++= '"'; + break; + case '\032': /* This gives problems on Win32 */ + *to++= '\\'; + *to++= 'Z'; + break; + default: + *to++= *from; + } + } + *to=0; + return (ulong) (to-to_start); +} + + +char * STDCALL +mysql_odbc_escape_string(MYSQL *mysql, + char *to, ulong to_length, + const char *from, ulong from_length, + void *param, + char * (*extend_buffer) + (void *, char *, ulong *)) +{ + char *to_end=to+to_length-5; + const char *end; +#ifdef USE_MB + my_bool use_mb_flag=use_mb(mysql->charset); +#endif + + for (end=from+from_length; from != end ; from++) + { + if (to >= to_end) + { + to_length = (ulong) (end-from)+512; /* We want this much more */ + if (!(to=(*extend_buffer)(param, to, &to_length))) + return to; + to_end=to+to_length-5; + } +#ifdef USE_MB + { + int l; + if (use_mb_flag && (l = my_ismbchar(mysql->charset, from, end))) + { + while (l--) + *to++ = *from++; + from--; + continue; + } + } +#endif + switch (*from) { + case 0: /* Must be escaped for 'mysql' */ + *to++= '\\'; + *to++= '0'; + break; + case '\n': /* Must be escaped for logs */ + *to++= '\\'; + *to++= 'n'; + break; + case '\r': + *to++= '\\'; + *to++= 'r'; + break; + case '\\': + *to++= '\\'; + *to++= '\\'; + break; + case '\'': + *to++= '\\'; + *to++= '\''; + break; + case '"': /* Better safe than sorry */ + *to++= '\\'; + *to++= '"'; + break; + case '\032': /* This gives problems on Win32 */ + *to++= '\\'; + *to++= 'Z'; + break; + default: + *to++= *from; + } + } + return to; +} + +void STDCALL +myodbc_remove_escape(MYSQL *mysql,char *name) +{ + char *to; +#ifdef USE_MB + my_bool use_mb_flag=use_mb(mysql->charset); + char *end; + LINT_INIT(end); + if (use_mb_flag) + for (end=name; *end ; end++) ; +#endif + + for (to=name ; *name ; name++) + { +#ifdef USE_MB + int l; + if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) ) + { + while (l--) + *to++ = *name++; + name--; + continue; + } +#endif + if (*name == '\\' && name[1]) + name++; + *to++= *name; + } + *to=0; +} + + + + diff --git a/man/Makefile.am b/man/Makefile.am index 186fc01685e..7019d2aa865 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -19,7 +19,7 @@ man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \ mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \ - perror.1 replace.1 safe_mysqld.1 + perror.1 replace.1 mysqld_safe.1 EXTRA_DIST = $(man_MANS) diff --git a/man/isamchk.1 b/man/isamchk.1 index f225dc35d18..2552d9f80cd 100755..100644 --- a/man/isamchk.1 +++ b/man/isamchk.1 @@ -125,7 +125,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/isamlog.1 b/man/isamlog.1 index efc042ccd7c..ef6ceaff8da 100644 --- a/man/isamlog.1 +++ b/man/isamlog.1 @@ -83,7 +83,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), diff --git a/man/mysql.1 b/man/mysql.1 index 96ccca8f50e..e10fd589092 100644 --- a/man/mysql.1 +++ b/man/mysql.1 @@ -111,7 +111,7 @@ executable .I /depot/bin/mysqld executable .TP -.I /depot/bin/safe_mysqld +.I /depot/bin/mysqld_safe executable shell script for starting mysqld safely .TP .I /site/var/mysql/data @@ -135,7 +135,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysql_zap.1 b/man/mysql_zap.1 index 98da195894e..e57eb7a4d07 100644 --- a/man/mysql_zap.1 +++ b/man/mysql_zap.1 @@ -28,7 +28,7 @@ isn't given, ask user for confirmation for each process to kill. If signal isn't .BR -t is given the processes is only shown on stdout. .SH "SEE ALSO" -isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), safe_mysqld (1), which1 (1), zap (1), +isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). This software comes with no warranty. Manual page by L. (Kill-9) Pedersen (kill-9@kill-9.dk), Mercurmedia Data Model Architect / system developer (http://www.mercurmedia.com) .\" end of man page
\ No newline at end of file diff --git a/man/mysqlaccess.1 b/man/mysqlaccess.1 index 888cfe8f646..0ae06dca137 100755..100644 --- a/man/mysqlaccess.1 +++ b/man/mysqlaccess.1 @@ -106,7 +106,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysqladmin.1 b/man/mysqladmin.1 index 58bd2070de6..1e435006bb2 100755..100644 --- a/man/mysqladmin.1 +++ b/man/mysqladmin.1 @@ -189,7 +189,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysqld.1 b/man/mysqld.1 index d3f22c0be1b..1f87eb9cf32 100755..100644 --- a/man/mysqld.1 +++ b/man/mysqld.1 @@ -137,7 +137,7 @@ Don't check the rows in the table if there isn't any delete blocks. Before a table is automaticly repaired, mysqld will add a note about this in the error log. If you want to be able to recover from most things without user intervention, you should use the options BACKUP,FORCE. This will force a repair of a table even if some rows would be deleted, but it will keep the old data file as a backup so that you can later examine what happened. .TP .BR \-\-pid\-file=\fP\fIpath \fP -Path to pid file used by safe_mysqld. +Path to pid file used by mysqld_safe. .TP .BR \-P | \-\-port=... Port number to listen for TCP/IP connections. @@ -215,7 +215,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysqld_multi.1 b/man/mysqld_multi.1 index b68050e92ef..b7aa77f656d 100644 --- a/man/mysqld_multi.1 +++ b/man/mysqld_multi.1 @@ -36,7 +36,7 @@ Log file. Full path to and the name for the log file. NOTE: If the file exists, mysqladmin binary to be used for a server shutdown. .TP .BR --mysqld=... -mysqld binary to be used. Note that you can give safe_mysqld to this option also. The options are passed to mysqld. Just make sure you have mysqld in your environment variable PATH or fix safe_mysqld. +mysqld binary to be used. Note that you can give mysqld_safe to this option also. The options are passed to mysqld. Just make sure you have mysqld in your environment variable PATH or fix mysqld_safe. .TP .BR --no-log Print to stdout instead of the log file. By default the log file is turned on. @@ -70,7 +70,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), diff --git a/man/safe_mysqld.1 b/man/mysqld_safe.1 index 30abf04ae6b..bffbecd6478 100755..100644 --- a/man/safe_mysqld.1 +++ b/man/mysqld_safe.1 @@ -1,9 +1,9 @@ .TH SAFE_MYSQLD 1 "19 December 2000" .SH NAME -.BR safe_mysqld -is the recommended way to start a mysqld daemon on Unix. safe_mysqld adds some safety features such as restarting the server when an error occurs and logging run-time information to a log file. +.BR mysqld_safe +is the recommended way to start a mysqld daemon on Unix. mysqld_safe adds some safety features such as restarting the server when an error occurs and logging run-time information to a log file. .SH SYNOPSIS -.B safe_mysqld +.B mysqld_safe .RB [ \-\-basedir=\fP\fIpath\fP ] .RB [ \-\-core\-file\-size=# ] .RB [ \-\-defaults\-extra\-file=\fP\fIpath\fP ] @@ -58,7 +58,7 @@ Set the timezone (the TZ) variable to the value of this parameter. .TP .BR \-\-user=# .SH NOTE -Note that all options on the command line to safe_mysqld are passed to mysqld. If you wants to use any options in safe_mysqld that mysqld doesn't support, you must specify these in the option file. +Note that all options on the command line to mysqld_safe are passed to mysqld. If you wants to use any options in mysqld_safe that mysqld doesn't support, you must specify these in the option file. .SH "SEE ALSO" isamchk (1), isamlog (1), @@ -71,7 +71,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysqldump.1 b/man/mysqldump.1 index f108da17bf9..b9e5aa33791 100755..100644 --- a/man/mysqldump.1 +++ b/man/mysqldump.1 @@ -258,7 +258,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/mysqlshow.1 b/man/mysqlshow.1 index 55a87c1df78..661b2cd02c8 100755..100644 --- a/man/mysqlshow.1 +++ b/man/mysqlshow.1 @@ -78,7 +78,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/perror.1 b/man/perror.1 index 2853f2cb1ba..7adf99ea772 100755..100644 --- a/man/perror.1 +++ b/man/perror.1 @@ -43,7 +43,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/replace.1 b/man/replace.1 index 10bcf64fc88..38ffe998027 100644 --- a/man/replace.1 +++ b/man/replace.1 @@ -52,7 +52,7 @@ mysqlshow (1), msql2mysql (1), perror (1), replace (1), -safe_mysqld (1), +mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR diff --git a/man/which.2 b/man/which.2 index 599b68080a2..30d5557ed01 100644 --- a/man/which.2 +++ b/man/which.2 @@ -48,7 +48,7 @@ Ignore option .BR --read-alias; don\'t read stdin. .SH "SEE ALSO" -isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), safe_mysqld (1), which1 (1), zap (1), +isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1), .SH AUTHOR Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). This software comes with no warranty. Manual page by L. (Kill-9) Pedersen (kill-9@kill-9.dk), Mercurmedia Data Model Architect / system developer (http://www.mercurmedia.com) .\" end of man page
\ No newline at end of file diff --git a/merge/open.c b/merge/open.c index c1be98b7e18..7b5e571b9ad 100644 --- a/merge/open.c +++ b/merge/open.c @@ -36,7 +36,7 @@ int mode, int handle_locking) { int save_errno,i,errpos; - uint files,dir_length,length; + uint files,dir_length,length, options; ulonglong file_offset; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; MRG_INFO info,*m_info; @@ -90,16 +90,22 @@ int handle_locking) m_info->open_tables=(MRG_TABLE *) (m_info+1); m_info->tables=files; + options= (uint) ~0; for (i=files ; i-- > 0 ; ) { m_info->open_tables[i].table=isam; m_info->options|=isam->s->base.options; + options&=isam->s->base.options; m_info->records+=isam->s->state.records; m_info->del+=isam->s->state.del; m_info->data_file_length=isam->s->state.data_file_length; if (i) isam=(N_INFO*) (isam->open_list.next->data); } + /* Don't force readonly if not all tables are readonly */ + if (! (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA))) + m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); + /* Fix fileinfo for easyer debugging (actually set by rrnd) */ file_offset=0; for (i=0 ; (uint) i < files ; i++) diff --git a/myisam/Makefile.am b/myisam/Makefile.am index a18ff55ba9e..6781116043f 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -1,15 +1,15 @@ # Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB -# +# # 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 @@ -17,7 +17,7 @@ EXTRA_DIST = mi_test_all.sh mi_test_all.res pkgdata_DATA = mi_test_all mi_test_all.res -INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include +INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a pkglib_LIBRARIES = libmyisam.a @@ -25,13 +25,14 @@ bin_PROGRAMS = myisamchk myisamlog myisampack myisamchk_DEPENDENCIES= $(LIBRARIES) myisamlog_DEPENDENCIES= $(LIBRARIES) myisampack_DEPENDENCIES=$(LIBRARIES) -noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval +noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval ft_dump noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h mi_test1_DEPENDENCIES= $(LIBRARIES) mi_test2_DEPENDENCIES= $(LIBRARIES) mi_test3_DEPENDENCIES= $(LIBRARIES) ft_test1_DEPENDENCIES= $(LIBRARIES) ft_eval_DEPENDENCIES= $(LIBRARIES) +ft_dump_DEPENDENCIES= $(LIBRARIES) libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_rnext.c mi_rnext_same.c \ mi_search.c mi_page.c mi_key.c mi_locking.c \ @@ -45,7 +46,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_changed.c mi_static.c mi_delete_all.c \ mi_delete_table.c mi_rename.c mi_check.c \ ft_parser.c ft_search.c ft_stopwords.c ft_static.c \ - ft_update.c sort.c + ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all DEFS = -DMAP_TO_USE_RAID # Omit dependency for ../mit-pthreads/include/sys that only exits if diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c new file mode 100644 index 00000000000..3562e05006a --- /dev/null +++ b/myisam/ft_boolean_search.c @@ -0,0 +1,224 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +/* search with boolean queries */ + +typedef struct st_all_in_one { + MI_INFO *info; + uint keynr; + uchar *keybuff; + MI_KEYDEF *keyinfo; + my_off_t key_root; + TREE dtree; + byte *start, *end; + uint total_yes, total_no; +} ALL_IN_ONE; + +typedef struct st_ft_superdoc { + FT_DOC doc; + //FT_WORD *word_ptr; + //double tmp_weight; + uint yes; + uint no; + uint wno; + ALL_IN_ONE *aio; +} FT_SUPERDOC; + +static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), + FT_SUPERDOC *p1, FT_SUPERDOC *p2) +{ + if (p1->doc.dpos < p2->doc.dpos) + return -1; + if (p1->doc.dpos == p2->doc.dpos) + return 0; + return 1; +} + +static int walk_and_copy(FT_SUPERDOC *from, + uint32 count __attribute__((unused)), FT_DOC **to) +{ + if (from->yes == from->aio->total_yes && !from->no) + { + (*to)->dpos=from->doc.dpos; + (*to)->weight=from->doc.weight; + (*to)++; + } + return 0; +} + +static double _wghts[11]={ + 0.131687242798354, + 0.197530864197531, + 0.296296296296296, + 0.444444444444444, + 0.666666666666667, + 1.000000000000000, + 1.500000000000000, + 2.250000000000000, + 3.375000000000000, + 5.062500000000000, + 7.593750000000000}; +static double *wghts=_wghts+5; // wghts[i] = 1.5**i + +static double _nwghts[11]={ + -0.065843621399177, + -0.098765432098766, + -0.148148148148148, + -0.222222222222222, + -0.333333333333334, + -0.500000000000000, + -0.750000000000000, + -1.125000000000000, + -1.687500000000000, + -2.531250000000000, + -3.796875000000000}; +static double *nwghts=_nwghts+5; // nwghts[i] = -0.5*1.5**i + +int do_boolean(ALL_IN_ONE *aio, uint nested __attribute__((unused)), + int yesno __attribute__((unused)), + int plusminus, bool pmsign) +{ + int r, res; + uint keylen, wno; + FT_SUPERDOC sdoc, *sptr; + TREE_ELEMENT *selem; + FT_WORD w; + FTB_PARAM param; + +#ifdef EVAL_RUN + return 1; +#endif /* EVAL_RUN */ + + param.prev=' '; + + for(wno=1; (res=ft_get_word(&aio->start,aio->end,&w,¶m)); wno++) + { + r=plusminus+param.plusminus; + if (param.pmsign^pmsign) + w.weight=nwghts[(r>5)?5:((r<-5)?-5:r)]; + else + w.weight=wghts[(r>5)?5:((r<-5)?-5:r)]; + + if (param.yesno>0) aio->total_yes++; + if (param.yesno<0) aio->total_no++; + + switch (res) { + case FTB_LBR: // ( + //if (do_boolean(aio,nested+1,my_yesno,plusminus+my_plusminus)) + // return 1; + // ??? + break; + case 1: // word + keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,&w,0); + keylen-=HA_FT_WLEN; + + r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, + SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + + while (!r) + { + if (param.trunc) + r=_mi_compare_text(default_charset_info, + aio->info->lastkey+1,keylen-1, + aio->keybuff+1,keylen-1,0); + else + r=_mi_compare_text(default_charset_info, + aio->info->lastkey,keylen, + aio->keybuff,keylen,0); + if (r) break; + + sdoc.doc.dpos=aio->info->lastpos; + + /* saving document matched into dtree */ + if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; + + sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); + + if (selem->count==1) /* document's first match */ + { + sptr->yes=sptr->no=sptr->doc.weight=0; + sptr->aio=aio; + sptr->wno=0; + } + if (sptr->wno != wno) + { + if (param.yesno>0) sptr->yes++; + if (param.yesno<0) sptr->no++; + sptr->wno=wno; + } + sptr->doc.weight+=w.weight; + + if (_mi_test_if_changed(aio->info) == 0) + r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + else + r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + } + break; + case FTB_RBR: // ) + break; + } + } + return 0; +} + +FT_DOCLIST *ft_boolean_search(MI_INFO *info, uint keynr, byte *query, + uint query_len) +{ + ALL_IN_ONE aio; + FT_DOC *dptr; + FT_DOCLIST *dlist=NULL; + + aio.info=info; + aio.keynr=keynr; + aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; + aio.keyinfo=aio.info->s->keyinfo+keynr; + aio.key_root=aio.info->s->state.key_root[keynr]; + aio.start=query; + aio.end=query+query_len; + aio.total_yes=aio.total_no=0; + + init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, + NULL, NULL); + + if (do_boolean(&aio,0,0,0,0)) + goto err; + + dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0)); + if(!dlist) + goto err; + + dlist->ndocs=aio.dtree.elements_in_tree; + dlist->curdoc=-1; + dlist->info=aio.info; + dptr=dlist->doc; + + tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right); + + dlist->ndocs=dptr - dlist->doc; + +err: + delete_tree(&aio.dtree); + return dlist; +} + diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c new file mode 100644 index 00000000000..bb308188969 --- /dev/null +++ b/myisam/ft_dump.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +static void get_options(int argc,char *argv[]); +static void usage(char *argv[]); +static void complain(int val); + +static int count=0, stats=0, dump=0, verbose=0; +static char *query=NULL; + +#define MAX (HA_FT_MAXLEN+10) +#define HOW_OFTEN_TO_WRITE 1000 + +int main(int argc,char *argv[]) +{ + int error=0; + uint keylen, inx, doc_cnt=0; + float weight; + double gws, min_gws=0, avg_gws=0; + MI_INFO *info; + char buf[MAX], buf2[MAX], buf_maxlen[MAX], buf_min_gws[MAX]; + ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0; +#ifdef EVAL_RUN + uint cnt; + double sum, sum2, suml; +#endif /* EVAL_RUN */ + struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ + + MY_INIT(argv[0]); + get_options(argc,argv); + if (count || dump) + verbose=0; + else + stats=1; + + if (verbose) + setbuf(stdout,NULL); + + if (argc-optind < 2) + usage(argv); + + if (!(info=mi_open(argv[optind],2,HA_OPEN_ABORT_IF_LOCKED))) + goto err; + + inx=atoi(argv[optind+1]); + *buf2=0; + aio->info=info; + + if ((inx >= info->s->base.keys) || !(info->s->keyinfo[inx].flag & HA_FULLTEXT)) + { + printf("Key %d in table %s is not a FULLTEXT key\n", inx, info->filename); + goto err; + } + + if (query) + { + FT_DOCLIST *result; + int i; + + ft_init_stopwords(ft_precompiled_stopwords); + + result=ft_init_search(info,inx,query,strlen(query),1); + if(!result) + goto err; + + if (verbose) + printf("%d rows matched\n",result->ndocs); + + for(i=0 ; i<result->ndocs ; i++) + printf("%9qx %20.7f\n",result->doc[i].dpos,result->doc[i].weight); + + ft_close_search(result); + } + else + { + info->lastpos= HA_OFFSET_ERROR; + info->update|= HA_STATE_PREV_FOUND; + + while (!(error=mi_rnext(info,NULL,inx))) + { + keylen=*(info->lastkey); + +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT +#ifdef EVAL_RUN + mi_float4get(weight,info->lastkey+keylen+2); +#else /* EVAL_RUN */ + mi_float4get(weight,info->lastkey+keylen+1); +#endif /* EVAL_RUN */ +#else +#error +#endif + +#ifdef EVAL_RUN + cnt=*(byte *)(info->lastkey+keylen); +#endif /* EVAL_RUN */ + + snprintf(buf,MAX,"%.*s",(int) keylen,info->lastkey+1); + casedn_str(buf); + total++; + + if (count || stats) + { + doc_cnt++; +#ifdef EVAL_RUN + sum +=cnt; + sum2+=cnt*cnt; + suml+=cnt*log(cnt); +#endif /* EVAL_RUN */ + if (strcmp(buf, buf2)) + { + if (*buf2) + { + uniq++; + avg_gws+=gws=GWS_IN_USE; + if (count) + printf("%9u %20.7f %s\n",doc_cnt,gws,buf2); + if (maxlen<keylen) + { + maxlen=keylen; + strcpy(buf_maxlen, buf2); + } + if (max_doc_cnt < doc_cnt) + { + max_doc_cnt=doc_cnt; + strcpy(buf_min_gws, buf2); + min_gws=gws; + } + } + strcpy(buf2, buf); +#ifdef EVAL_RUN + sum=sum2=suml= +#endif /* EVAL_RUN */ + doc_cnt=0; + } + } + if (dump) + printf("%9qx %20.7f %s\n",info->lastpos,weight,buf); + + if(verbose && (total%HOW_OFTEN_TO_WRITE)==0) + printf("%10ld\r",total); + } + + if (stats) + printf("Total rows: %qu\nTotal words: %lu\n" + "Unique words: %lu\nLongest word: %lu chars (%s)\n" + "Average global weight: %f\n" + "Most common word: %lu times, weight: %f (%s)\n", + (ulonglong)info->state->records, total, uniq, maxlen, buf_maxlen, + avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws); + } + +err: + if (error && error != HA_ERR_END_OF_FILE) + printf("got error %d\n",my_errno); + if (info) + mi_close(info); + return 0; +} + +const char *options="dscve:h"; + +static void get_options(int argc, char *argv[]) +{ + int c; + + while ((c=getopt(argc,argv,options)) != -1) + { + switch(c) { + case 'd': dump=1; complain(count || query); break; + case 's': stats=1; complain(query!=0); break; + case 'v': verbose=1; break; + case 'c': count=1; complain(dump || query); break; + case 'e': query=my_strdup(optarg,MYF(MY_FAE)); complain(dump || count || stats); break; + case '?': + case 'h': + default: + usage(argv); + } + } + return; +} /* get options */ + +static void usage(char *argv[]) +{ + printf("Use: %s [-%s] <table_name> <key_no>\n", *argv, options); + exit(1); +} + +static void complain(int val) /* Kinda assert :-) */ +{ + if (val) + { + printf("You cannot use these options together!\n"); + exit(1); + } +} + diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c new file mode 100644 index 00000000000..350a60708f6 --- /dev/null +++ b/myisam/ft_nlq_search.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +/* search with natural language queries */ + +typedef struct st_all_in_one { + MI_INFO *info; + uint keynr; + uchar *keybuff; + MI_KEYDEF *keyinfo; + my_off_t key_root; + TREE dtree; +} ALL_IN_ONE; + +typedef struct st_ft_superdoc { + FT_DOC doc; + FT_WORD *word_ptr; + double tmp_weight; +} FT_SUPERDOC; + +static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), + FT_SUPERDOC *p1, FT_SUPERDOC *p2) +{ + if (p1->doc.dpos < p2->doc.dpos) + return -1; + if (p1->doc.dpos == p2->doc.dpos) + return 0; + return 1; +} + +static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) +{ + uint keylen, r, doc_cnt; +#ifdef EVAL_RUN + uint cnt; + double sum, sum2, suml; +#endif /* EVAL_RUN */ + FT_SUPERDOC sdoc, *sptr; + TREE_ELEMENT *selem; +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT + float tmp_weight; +#else +#error +#endif + + word->weight=LWS_FOR_QUERY; + + keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); +#ifdef EVAL_RUN + keylen-=1+HA_FT_WLEN; +#else /* EVAL_RUN */ + keylen-=HA_FT_WLEN; +#endif /* EVAL_RUN */ + +#ifdef EVAL_RUN + sum=sum2=suml= +#endif /* EVAL_RUN */ + doc_cnt=0; + + r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, + SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + + while(!r) + { + if (_mi_compare_text(default_charset_info, + aio->info->lastkey,keylen, + aio->keybuff,keylen,0)) break; + +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT +#ifdef EVAL_RUN + mi_float4get(tmp_weight,aio->info->lastkey+keylen+1); +#else /* EVAL_RUN */ + mi_float4get(tmp_weight,aio->info->lastkey+keylen); +#endif /* EVAL_RUN */ +#else +#error +#endif + if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */ + +#ifdef EVAL_RUN + cnt=*(byte *)(aio->info->lastkey+keylen); +#endif /* EVAL_RUN */ + + sdoc.doc.dpos=aio->info->lastpos; + + /* saving document matched into dtree */ + if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; + + sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); + + if(selem->count==1) /* document's first match */ + sptr->doc.weight=0; + else + sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight; + + sptr->word_ptr=word; + sptr->tmp_weight=tmp_weight; + + doc_cnt++; +#ifdef EVAL_RUN + sum +=cnt; + sum2+=cnt*cnt; + suml+=cnt*log(cnt); +#endif /* EVAL_RUN */ + + if (_mi_test_if_changed(aio->info) == 0) + r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + else + r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + } + if(doc_cnt) { + word->weight*=GWS_IN_USE; + if(word->weight < 0) word->weight=0; + } + + return 0; +} + +static int walk_and_copy(FT_SUPERDOC *from, + uint32 count __attribute__((unused)), FT_DOC **to) +{ + from->doc.weight+=from->tmp_weight*from->word_ptr->weight; + (*to)->dpos=from->doc.dpos; + (*to)->weight=from->doc.weight; + (*to)++; + return 0; +} + +FT_DOCLIST *ft_nlq_search(MI_INFO *info, uint keynr, byte *query, + uint query_len) +{ + TREE *wtree, allocated_wtree; + ALL_IN_ONE aio; + FT_DOC *dptr; + FT_DOCLIST *dlist=NULL; + + aio.info=info; + aio.keynr=keynr; + aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; + aio.keyinfo=aio.info->s->keyinfo+keynr; + aio.key_root=aio.info->s->state.key_root[keynr]; + + bzero(&allocated_wtree,sizeof(allocated_wtree)); + + init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, + NULL, NULL); + + if(!(wtree=ft_parse(&allocated_wtree,query,query_len))) + return NULL; + + if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio, + left_root_right)) + goto err; + + dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0)); + if(!dlist) + goto err; + + dlist->ndocs=aio.dtree.elements_in_tree; + dlist->curdoc=-1; + dlist->info=aio.info; + dptr=dlist->doc; + + tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right); + +err: + delete_tree(wtree); + delete_tree(&aio.dtree); + return dlist; +} + diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 7ea2e240c36..83b0956a752 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -38,7 +38,8 @@ typedef struct st_ft_docstat { byte *keybuf; } FT_DOCSTAT; -static int FT_WORD_cmp(FT_WORD *w1, FT_WORD *w2) +static int FT_WORD_cmp(void* cmp_arg __attribute__((unused)), + FT_WORD *w1, FT_WORD *w2) { return _mi_compare_text(default_charset_info, (uchar*) w1->pos,w1->len, @@ -67,6 +68,7 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) { FT_WORD *wlist,*p; FT_DOCSTAT docstat; + DBUG_ENTER("ft_linearize"); if ((wlist=(FT_WORD *) my_malloc(sizeof(FT_WORD)* (1+wtree->elements_in_tree),MYF(0)))) @@ -83,13 +85,12 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right); } delete_tree(wtree); - my_free((char*) wtree,MYF(0)); if (!wlist) - return NULL; + DBUG_RETURN(NULL); docstat.list->pos=NULL; - for(p=wlist;p->pos;p++) + for (p=wlist;p->pos;p++) { p->weight=PRENORM_IN_USE; #ifdef EVAL_RUN @@ -104,48 +105,140 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) #endif #endif /* EVAL_RUN */ - for(p=wlist;p->pos;p++) + for (p=wlist;p->pos;p++) { p->weight/=NORM_IN_USE; } - return wlist; + DBUG_RETURN(wlist); } +#define true_word_char(X) (isalnum(X) || (X)=='_') #ifdef HYPHEN_IS_DELIM -#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'') +#define misc_word_char(X) ((X)=='\'') #else -#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-') +#define misc_word_char(X) ((X)=='\'' || (X)=='-') #endif +#define word_char(X) (true_word_char(X) || misc_word_char(X)) -/* this is rather dumb first version of the parser */ -TREE * ft_parse(TREE *wtree, byte *doc, int doclen) +byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { - byte *end=doc+doclen; - FT_WORD w; + byte *doc=*start; + int mwc; + + param->yesno=param->plusminus=param->pmsign=0; - if (!wtree) + while (doc<end) { - if (!(wtree=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return NULL; - init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL); + for (;doc<end;doc++) + { + if (true_word_char(*doc)) break; + if (*doc == FTB_LBR || *doc == FTB_RBR) + { + param->prev=' '; + *start=doc+1; + return *doc; + } + if (param->prev == ' ') + { + switch (*doc) { + case FTB_YES: param->yesno=+1; continue; + case FTB_NO: param->yesno=-1; continue; + case FTB_INC: param->plusminus++; continue; + case FTB_DEC: param->plusminus--; continue; + case FTB_NEG: param->pmsign=!param->pmsign; continue; + default: break; + } + } + param->prev=*doc; + param->yesno=param->plusminus=param->pmsign=0; + } + + mwc=0; + for (word->pos=doc; doc<end; doc++) + if (true_word_char(*doc)) + mwc=0; + else if (!misc_word_char(*doc) || mwc++) + break; + + param->prev='A'; // be sure *prev is true_word_char + word->len= (uint)(doc-word->pos) - mwc; + if ((param->trunc=(doc<end && *doc == FTB_TRUNC))) + doc++; + + if (word->len >= ft_min_word_len && word->len < ft_max_word_len && + !is_stopword(word->pos, word->len)) + { + *start=doc; + return 1; + } } + return 0; +} + +byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word) +{ + byte *doc=*start; + int mwc; - w.weight=0; while (doc<end) { for (;doc<end;doc++) - if (word_char(*doc)) break; - for (w.pos=doc; doc<end; doc++) - if (!word_char(*doc)) break; - if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue; - if (w.len >= HA_FT_MAXLEN) continue; - if (is_stopword(w.pos, w.len)) continue; - if (!tree_insert(wtree, &w, 0)) { - delete_tree(wtree); - my_free((char*) wtree,MYF(0)); - return NULL; + if (true_word_char(*doc)) break; + } + + mwc=0; + for(word->pos=doc; doc<end; doc++) + if (true_word_char(*doc)) + mwc=0; + else if (!misc_word_char(*doc) || mwc++) + break; + + word->len= (uint)(doc-word->pos) - mwc; + + if (word->len >= ft_min_word_len && word->len < ft_max_word_len && + !is_stopword(word->pos, word->len)) + { + *start=doc; + return 1; } } + return 0; +} + +int is_boolean(byte *q, uint len) +{ + if (!len) return 0; + if (*q == FTB_YES || *q == FTB_NO) return 1; + + for (++q; --len; ++q) + { + if ((*q == FTB_YES || *q == FTB_NO) && q[-1] == ' ' && true_word_char(q[1])) + return 1; + } + return 0; +} + +TREE * ft_parse(TREE *wtree, byte *doc, int doclen) +{ + byte *end=doc+doclen; + FT_WORD w; + + if (!is_tree_inited(wtree)) + { + init_tree(wtree,0,0,sizeof(FT_WORD),(qsort_cmp2)&FT_WORD_cmp,0,NULL, NULL); + } + + while (ft_simple_get_word(&doc,end,&w)) + { + if (!tree_insert(wtree, &w, 0)) + goto err; + } return wtree; + +err: + delete_tree(wtree); + return NULL; } + diff --git a/myisam/ft_search.c b/myisam/ft_search.c index 9a728a4c211..c5a43734d9a 100644 --- a/myisam/ft_search.c +++ b/myisam/ft_search.c @@ -18,146 +18,17 @@ #include "ftdefs.h" -/* queries isam and returns list of documents matched */ - -typedef struct st_all_in_one { - MI_INFO *info; - uint keynr; - uchar *keybuff; - MI_KEYDEF *keyinfo; - my_off_t key_root; - TREE dtree; -} ALL_IN_ONE; - -typedef struct st_ft_superdoc { - FT_DOC doc; - FT_WORD *word_ptr; - double tmp_weight; -} FT_SUPERDOC; - -static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2) -{ - if (p1->doc.dpos < p2->doc.dpos) - return -1; - if (p1->doc.dpos == p2->doc.dpos) - return 0; - return 1; -} - -static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) -{ - uint keylen, r, doc_cnt; -#ifdef EVAL_RUN - uint cnt; - double sum, sum2, suml; -#endif /* EVAL_RUN */ - FT_SUPERDOC sdoc, *sptr; - TREE_ELEMENT *selem; -#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT - float tmp_weight; -#else -#error -#endif - - word->weight=LWS_FOR_QUERY; - - keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); -#ifdef EVAL_RUN - keylen-=1+HA_FT_WLEN; -#else /* EVAL_RUN */ - keylen-=HA_FT_WLEN; -#endif /* EVAL_RUN */ - -#ifdef EVAL_RUN - sum=sum2=suml= -#endif /* EVAL_RUN */ - doc_cnt=0; - - r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, - SEARCH_FIND | SEARCH_PREFIX, aio->key_root); - - while(!r) - { - if (_mi_compare_text(default_charset_info, - aio->info->lastkey,keylen, - aio->keybuff,keylen,0)) break; - -#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT -#ifdef EVAL_RUN - mi_float4get(tmp_weight,aio->info->lastkey+keylen+1); -#else /* EVAL_RUN */ - mi_float4get(tmp_weight,aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ -#else -#error -#endif - if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */ - -#ifdef EVAL_RUN - cnt=*(byte *)(aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ - - sdoc.doc.dpos=aio->info->lastpos; - - /* saving document matched into dtree */ - if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; - - sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); - - if(selem->count==1) /* document's first match */ - sptr->doc.weight=0; - else - sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight; - - sptr->word_ptr=word; - sptr->tmp_weight=tmp_weight; - - doc_cnt++; -#ifdef EVAL_RUN - sum +=cnt; - sum2+=cnt*cnt; - suml+=cnt*log(cnt); -#endif /* EVAL_RUN */ - - if (_mi_test_if_changed(aio->info) == 0) - r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); - else - r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); - } - if(doc_cnt) { - word->weight*=GWS_IN_USE; - if(word->weight < 0) word->weight=0; - } - - return 0; -} - -static int walk_and_copy(FT_SUPERDOC *from, - uint32 count __attribute__((unused)), FT_DOC **to) -{ - from->doc.weight+=from->tmp_weight*from->word_ptr->weight; - (*to)->dpos=from->doc.dpos; - (*to)->weight=from->doc.weight; - (*to)++; - return 0; -} +/* queries myisam and returns list of documents matched */ static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b) { return sgn(b->weight - a->weight); } -FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key, - uint key_len, my_bool presort) +FT_DOCLIST *ft_init_search(void *info, uint keynr, byte *query, + uint query_len, my_bool presort) { - TREE *wtree; - ALL_IN_ONE aio; FT_DOCLIST *dlist; - FT_DOC *dptr; my_off_t saved_lastpos=((MI_INFO *)info)->lastpos; /* black magic ON */ @@ -167,44 +38,16 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key, return NULL; /* black magic OFF */ - dlist=NULL; - aio.info=(MI_INFO *)info; - aio.keynr=keynr; - aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; - aio.keyinfo=aio.info->s->keyinfo+keynr; - aio.key_root=aio.info->s->state.key_root[keynr]; - - if (!(wtree=ft_parse(NULL,key,key_len))) return NULL; - - init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0, - NULL); - - if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio, - left_root_right)) - goto err; - - dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)* - (aio.dtree.elements_in_tree-1),MYF(0)); - if (!dlist) - goto err; - - dlist->ndocs=aio.dtree.elements_in_tree; - dlist->curdoc=-1; - dlist->info=aio.info; - dptr=dlist->doc; - - tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, - left_root_right); + if (is_boolean(query, query_len)) + dlist=ft_boolean_search(info,keynr,query,query_len); + else + dlist=ft_nlq_search(info,keynr,query,query_len); - if (presort) + if(dlist && presort) { qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp); } -err: - delete_tree(&aio.dtree); - delete_tree(wtree); - my_free((char*) wtree,MYF(0)); ((MI_INFO *)info)->lastpos=saved_lastpos; return dlist; } diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 00d9d4ed19a..09afadec23f 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -18,6 +18,10 @@ #include "ftdefs.h" +uint ft_min_word_len=4; +uint ft_max_word_len=HA_FT_MAXLEN; +uint ft_max_word_len_for_sort=20; + const MI_KEYSEG ft_keysegs[FT_SEGS]={ { HA_KEYTYPE_VARTEXT, /* type */ diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index d796b87ed71..8565a153b81 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -25,7 +25,8 @@ typedef struct st_ft_stopwords { static TREE *stopwords3=NULL; -static int FT_STOPWORD_cmp(FT_STOPWORD *w1, FT_STOPWORD *w2) +static int FT_STOPWORD_cmp(void* cmp_arg __attribute__((unused)), + FT_STOPWORD *w1, FT_STOPWORD *w2) { return _mi_compare_text(default_charset_info, (uchar *)w1->pos,w1->len, @@ -40,15 +41,15 @@ int ft_init_stopwords(const char **sws) if(!stopwords3) { if(!(stopwords3=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return -1; - init_tree(stopwords3,0,sizeof(FT_STOPWORD),(qsort_cmp)&FT_STOPWORD_cmp,0, - NULL); + init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp,0, + NULL, NULL); } if(!sws) return 0; for(;*sws;sws++) { - if( (sw.len= (uint) strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue; + if( (sw.len= (uint) strlen(sw.pos=*sws)) < ft_min_word_len) continue; if(!tree_insert(stopwords3, &sw, 0)) { delete_tree(stopwords3); /* purecov: inspected */ diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 753c4dc4029..1e00cc5d7a0 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -29,14 +29,16 @@ /* parses a document i.e. calls _mi_ft_parse for every keyseg */ -static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, +FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, const byte *record) { - TREE *parsed=NULL; + TREE *parsed, ptree; MI_KEYSEG *keyseg; byte *pos; uint i; + bzero(parsed=&ptree, sizeof(ptree)); + keyseg=info->s->keyinfo[keynr].seg; for (i=info->s->keyinfo[keynr].keysegs-FT_SEGS ; i-- ; ) { @@ -64,7 +66,7 @@ static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, return NULL; } /* Handle the case where all columns are NULL */ - if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0))) + if (!is_tree_inited(parsed) && !(parsed=ft_parse(parsed, (byte*) "", 0))) return NULL; return ft_linearize(info, keynr, keybuf, parsed); } @@ -155,6 +157,62 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2) return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL; } +/* update a document entry */ +int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, + const byte *oldrec, const byte *newrec, my_off_t pos) +{ + int error= -1; + FT_WORD *oldlist,*newlist, *old_word, *new_word; + uint key_length; + int cmp; + + if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec))) + goto err0; + if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec))) + goto err1; + + while(old_word->pos && new_word->pos) + { + cmp=_mi_compare_text(default_charset_info, + (uchar*) old_word->pos,old_word->len, + (uchar*) new_word->pos,new_word->len,0); + if (cmp==0) + cmp=sgn(old_word->weight-new_word->weight); + else + cmp=sgn(cmp); + + switch (cmp) { + case -1: + key_length=_ft_make_key(info,keynr,keybuf,old_word,pos); + if ((error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))) + goto err2; + old_word++; + break; + case 0: + old_word++; + new_word++; + break; + case 1: + key_length=_ft_make_key(info,keynr,keybuf,new_word,pos); + if ((error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))) + goto err2; + new_word++; + break; + } + } + if (old_word->pos) + error=_mi_ft_erase(info,keynr,keybuf,old_word,pos); + else if (new_word->pos) + error=_mi_ft_store(info,keynr,keybuf,new_word,pos); + +err2: + my_free((char*) newlist,MYF(0)); +err1: + my_free((char*) oldlist,MYF(0)); +err0: + return error; +} + /* adds a document to the collection */ int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, my_off_t pos) diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index d9b4ff6b44d..1a017d3c73a 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + 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 */ @@ -22,15 +22,18 @@ #include <m_ctype.h> #include <my_tree.h> -#define MIN_WORD_LEN 4 - #define HYPHEN_IS_DELIM #define HYPHEN_IS_CONCAT /* not used for now */ #define COMPILE_STOPWORDS_IN -/* Most of the formulae were shamelessly stolen from SMART distribution - ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z +/* Interested readers may consult SMART + (ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z) + for an excellent implementation of vector space model we use. + It also demonstrate the usage of different weghting techniques. + This code, though, is completely original and is not based on the + SMART code but was in some cases inspired by it. + NORM_PIVOT was taken from the article A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization", ACM SIGIR'96, 21-29, 1996 @@ -82,6 +85,19 @@ extern ulong collstat; #define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records)) /*=================================================================*/ +/* Boolean search operators */ +#define FTB_YES '+' +#define FTB_NO '-' +#define FTB_INC '>' +#define FTB_DEC '<' +#define FTB_LBR '(' +#define FTB_RBR ')' +#define FTB_NEG '~' +#define FTB_TRUNC '*' + +// #define FTB_MAX_SUBEXPR 255 +// #define FTB_MAX_DEPTH 16 + typedef struct st_ft_word { byte * pos; uint len; @@ -91,9 +107,26 @@ typedef struct st_ft_word { #endif /* EVAL_RUN */ } FT_WORD; +typedef struct st_ftb_param { + byte prev; + int yesno; + int plusminus; + bool pmsign; + bool trunc; +} FTB_PARAM; + int is_stopword(char *word, uint len); +int is_boolean(byte *q, uint len); uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t); +byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *); +byte ft_simple_get_word(byte **, byte *, FT_WORD *); + TREE * ft_parse(TREE *, byte *, int); FT_WORD * ft_linearize(MI_INFO *, uint, byte *, TREE *); +FT_WORD * _mi_ft_parserecord(MI_INFO *, uint , byte *, const byte *); + +FT_DOCLIST * ft_nlq_search(MI_INFO *, uint, byte *, uint); +FT_DOCLIST * ft_boolean_search(MI_INFO *, uint, byte *, uint); + diff --git a/myisam/fulltext.h b/myisam/fulltext.h index 8fcac8172b1..f787c9bcfe8 100644 --- a/myisam/fulltext.h +++ b/myisam/fulltext.h @@ -24,7 +24,6 @@ /* shoudn't be def'ed when linking with mysql */ #undef EVAL_RUN -#define HA_FT_MAXLEN 254 #define HA_FT_WTYPE HA_KEYTYPE_FLOAT #define HA_FT_WLEN 4 #ifdef EVAL_RUN diff --git a/myisam/mi_cache.c b/myisam/mi_cache.c index 69a1cb0d7a5..6c23916c645 100644 --- a/myisam/mi_cache.c +++ b/myisam/mi_cache.c @@ -73,6 +73,9 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length, if (!(flag & READING_HEADER) || info->error == -1 || (uint) info->error+in_buff_length < 3) { + DBUG_PRINT("error", + ("Error %d reading next-multi-part block (Got %d bytes)", + my_errno, info->error)); if (!my_errno || my_errno == -1) my_errno=HA_ERR_WRONG_IN_RECORD; DBUG_RETURN(1); @@ -87,6 +90,9 @@ int _mi_read_cache(IO_CACHE *info, byte *buff, my_off_t pos, uint length, if (!(flag & READING_HEADER) || (int) read_length == -1 || read_length+in_buff_length < 3) { + DBUG_PRINT("error", + ("Error %d reading new block (Got %d bytes)", + my_errno, (int) read_length)); if (!my_errno || my_errno == -1) my_errno=HA_ERR_WRONG_IN_RECORD; DBUG_RETURN(1); diff --git a/myisam/mi_check.c b/myisam/mi_check.c index aedea3ca78b..a15427b7838 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -16,7 +16,7 @@ /* Descript, check and repair of ISAM tables */ -#include "fulltext.h" +#include "ftdefs.h" #include <m_ctype.h> #include <stdarg.h> #include <getopt.h> @@ -45,6 +45,7 @@ static int writekeys(MI_INFO *info,byte *buff,my_off_t filepos); static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo, my_off_t pagepos, File new_file); static int sort_key_read(SORT_INFO *sort_info,void *key); +static int sort_ft_key_read(SORT_INFO *sort_info,void *key); static int sort_get_next_record(SORT_INFO *sort_info); static int sort_key_cmp(SORT_INFO *sort_info, const void *a,const void *b); static int sort_key_write(SORT_INFO *sort_info, const void *a); @@ -53,7 +54,7 @@ static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo, static int sort_insert_key(MI_CHECK *param, reg1 SORT_KEY_BLOCKS *key_block, uchar *key, my_off_t prev_block); static int sort_delete_record(MI_CHECK *param); -static int flush_pending_blocks(MI_CHECK *param); +/*static int flush_pending_blocks(MI_CHECK *param);*/ static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks, uint buffer_length); static void update_key_parts(MI_KEYDEF *keyinfo, @@ -102,6 +103,7 @@ void myisamchk_init(MI_CHECK *param) int chk_status(MI_CHECK *param, register MI_INFO *info) { MYISAM_SHARE *share=info->s; + if (mi_is_crashed_on_repair(info)) mi_check_print_warning(param, "Table is marked as crashed and last repair failed"); @@ -1117,6 +1119,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, share->pack.header_length; got_error=1; new_file= -1; + sort_info->buff=0; + sort_info->buff_length=0; + sort_info->record=0; + if (!(param->testflag & T_SILENT)) { printf("- recovering (with keycache) MyISAM-table '%s'\n",name); @@ -1129,7 +1135,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (init_io_cache(¶m->read_cache,info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME))) + { + bzero(&info->rec_cache,sizeof(info->rec_cache)); goto err; + } if (!rep_quick) if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length, WRITE_CACHE, new_header_length, 1, @@ -1137,7 +1146,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, goto err; info->opt_flag|=WRITE_CACHE_USED; sort_info->start_recpos=0; - sort_info->buff=0; sort_info->buff_length=0; if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength, MYF(0)))) { @@ -1147,7 +1155,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (!rep_quick) { - if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"", + /* Get real path for data file */ + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + if ((new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename,"", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, @@ -1309,11 +1320,11 @@ err: { my_close(new_file,MYF(0)); info->dfile=new_file= -1; - if (change_to_newfile(share->filename,MI_NAME_DEXT, + if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT, share->base.raid_chunks, (param->testflag & T_BACKUP_DATA ? MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || - mi_open_datafile(info,share)) + mi_open_datafile(info,share,-1)) got_error=1; } } @@ -1491,8 +1502,10 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) if (!(param->testflag & T_SILENT)) printf("- Sorting index for MyISAM-table '%s'\n",name); - if ((new_file=my_create(fn_format(param->temp_filename,name,"", - INDEX_TMP_EXT,2+4), + /* Get real path for index file */ + fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32); + if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename, + "", INDEX_TMP_EXT,2+4), 0,param->tmpfile_createflag,MYF(0))) <= 0) { mi_check_print_error(param,"Can't create new tempfile: '%s'", @@ -1512,7 +1525,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) if (share->state.key_root[key] != HA_OFFSET_ERROR) { - index_pos[key]=param->new_file_pos; /* Write first block here */ + index_pos[key]=param->new_file_pos; /* Write first block here */ if (sort_one_index(param,info,keyinfo,share->state.key_root[key], new_file)) goto err; @@ -1533,7 +1546,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) VOID(my_close(share->kfile,MYF(MY_WME))); share->kfile = -1; VOID(my_close(new_file,MYF(MY_WME))); - if (change_to_newfile(share->filename,MI_NAME_IEXT,INDEX_TMP_EXT,0, + if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0, MYF(0)) || mi_open_keyfile(share)) goto err2; @@ -1633,9 +1646,14 @@ err: } /* sort_one_index */ - /* Change to use new file */ - /* Copy stats from old file to new file, deletes orginal and */ - /* changes new file name to old file name */ + /* + Let temporary file replace old file. + This assumes that the new file was created in the same + directory as given by realpath(filename). + This will ensure that any symlinks that are used will still work. + Copy stats from old file to new file, deletes orignal and + changes new file name to old file name + */ int change_to_newfile(const char * filename, const char * old_ext, const char * new_ext, @@ -1650,8 +1668,10 @@ int change_to_newfile(const char * filename, const char * old_ext, raid_chunks, MYF(MY_WME | MY_LINK_WARNING | MyFlags)); #endif - return my_redel(fn_format(old_filename,filename,"",old_ext,2+4), - fn_format(new_filename,filename,"",new_ext,2+4), + /* Get real path to filename */ + (void) fn_format(old_filename,filename,"",old_ext,2+4+32); + return my_redel(old_filename, + fn_format(new_filename,old_filename,"",new_ext,2+4), MYF(MY_WME | MY_LINK_WARNING | MyFlags)); } /* change_to_newfile */ @@ -1742,22 +1762,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, printf("Data records: %s\n", llstr(start_records,llbuff)); } - /* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly - implies "one row - one key per keynr", while for ft_key one row/keynr - can produce as many keys as the number of unique words in the text - that's why I disabled repair_by_sort for ft-keys. (serg) - */ - for (i=0 ; i < share->base.keys ; i++) - { - if ((((ulonglong) 1 << i) & key_map) && - (share->keyinfo[i].flag & HA_FULLTEXT)) - { - mi_check_print_error(param, - "Can`t use repair_by_sort with FULLTEXT key"); - DBUG_RETURN(1); - } - } - bzero((char*) sort_info,sizeof(*sort_info)); if (!(sort_info->key_block= alloc_key_blocks(param, @@ -1784,7 +1788,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, } if (!rep_quick) { - if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"", + /* Get real path for data file */ + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + if ((new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename, "", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, @@ -1849,6 +1856,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, param->read_cache.end_of_file=sort_info->filelength= my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0)); + sort_info->wordlist=NULL; + if (share->data_file_type == DYNAMIC_RECORD) length=max(share->base.min_pack_length+1,share->base.min_block_length); else if (share->data_file_type == COMPRESSED_RECORD) @@ -1860,7 +1869,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, (ha_rows) (sort_info->filelength/length+1)); sort_param.key_cmp=sort_key_cmp; sort_param.key_write=sort_key_write; - sort_param.key_read=sort_key_read; sort_param.lock_in_memory=lock_memory; sort_param.tmpdir=param->tmpdir; sort_param.myf_rw=param->myf_rw; @@ -1905,6 +1913,17 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, info->state->records=info->state->del=share->state.split=0; info->state->empty=0; + if (sort_info->keyinfo->flag & HA_FULLTEXT) + { + sort_param.max_records=sort_info->max_records= + (ha_rows) (sort_info->filelength/ft_max_word_len_for_sort+1); + + sort_param.key_read=sort_ft_key_read; + sort_param.key_length+=ft_max_word_len_for_sort-ft_max_word_len; + } + else + sort_param.key_read=sort_key_read; + if (_create_index_by_sort(&sort_param, (my_bool) (!(param->testflag & T_VERBOSE)), (uint) param->sort_buffer_length)) @@ -1949,8 +1968,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, else info->state->data_file_length=sort_info->max_pos; - if (flush_pending_blocks(param)) - goto err; + /*if (flush_pending_blocks(param)) + goto err;*/ param->read_cache.file=info->dfile; /* re-init read cache */ reinit_io_cache(¶m->read_cache,READ_CACHE,share->pack.header_length,1, @@ -2016,11 +2035,11 @@ err: { my_close(new_file,MYF(0)); info->dfile=new_file= -1; - if (change_to_newfile(share->filename,MI_NAME_DEXT, + if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT, share->base.raid_chunks, (param->testflag & T_BACKUP_DATA ? MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || - mi_open_datafile(info,share)) + mi_open_datafile(info,share,-1)) got_error=1; } } @@ -2074,11 +2093,54 @@ static int sort_key_read(SORT_INFO *sort_info, void *key) "Found too many records; Can`t continue"); DBUG_RETURN(1); } - (void) _mi_make_key(info,sort_info->key,(uchar*)key,sort_info->record, - sort_info->filepos); + sort_info->real_key_length=(info->s->rec_reflength+ + _mi_make_key(info, sort_info->key, + (uchar*) key, sort_info->record, + sort_info->filepos)); DBUG_RETURN(sort_write_record(sort_info)); } /* sort_key_read */ +static int sort_ft_key_read(SORT_INFO *sort_info, void *key) +{ + int error; + MI_INFO *info; + FT_WORD *wptr; + DBUG_ENTER("sort_ft_key_read"); + + info=sort_info->info; + + if (!sort_info->wordlist) + { + do + { + if ((error=sort_get_next_record(sort_info))) + DBUG_RETURN(error); + if (!(wptr=_mi_ft_parserecord(info,sort_info->key,key,sort_info->record))) + DBUG_RETURN(1); + error=sort_write_record(sort_info); + } + while (!wptr->pos); + sort_info->wordptr=sort_info->wordlist=wptr; + } + else + { + error=0; + wptr=(FT_WORD*)(sort_info->wordptr); + } + + sort_info->real_key_length=info->s->rec_reflength+_ft_make_key(info, + sort_info->key,key,wptr++,sort_info->filepos); + if (!wptr->pos) + { + my_free((char*) sort_info->wordlist, MYF(0)); + sort_info->wordlist=0; + } + else + sort_info->wordptr=(void*)wptr; + + + DBUG_RETURN(error); +} /* sort_ft_key_read */ /* Read next record from file using parameters in sort_info */ /* Return -1 if end of file, 0 if ok and > 0 if error */ @@ -2736,7 +2798,7 @@ static int sort_delete_record(MI_CHECK *param) /* Fix all pending blocks and flush everything to disk */ -static int flush_pending_blocks(MI_CHECK *param) +int flush_pending_blocks(MI_CHECK *param) { uint nod_flag,length; my_off_t filepos,key_file_length; @@ -2830,7 +2892,6 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) MI_STATUS_INFO status_info; uint unpack,key_parts; ha_rows max_records; - char name[FN_REFLEN]; ulonglong file_length,tmp_length; MI_CREATE_INFO create_info; @@ -2939,8 +3000,9 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) create_info.language = (param->language ? param->language : share.state.header.language); - if (mi_create(fn_format(name,filename,"",MI_NAME_IEXT, - 4+ (param->opt_follow_links ? 16 : 0)), + /* We don't have to handle symlinks here because we are using + HA_DONT_TOUCH_DATA */ + if (mi_create(filename, share.base.keys - share.state.header.uniques, keyinfo, share.base.fields, recdef, share.state.header.uniques, uniquedef, @@ -2950,7 +3012,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno); goto end; } - *org_info=mi_open(name,O_RDWR, + *org_info=mi_open(filename,O_RDWR, (param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED : (param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED); @@ -3203,15 +3265,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, return FALSE; /* Can't use sort */ for (i=0 ; i < share->base.keys ; i++,key++) { -/* It's to disable repair_by_sort for ft-keys. - Another solution would be to make ft-keys just too_big_key_for_sort, - but then they won't be disabled by dectivate_non_unique_index - and so they will be created at the first stage. As ft-key creation - is very time-consuming process, it's better to leave it to repair stage - but this repair shouldn't be repair_by_sort (serg) - */ - if ((!force && mi_too_big_key_for_sort(key,rows)) || - (key->flag & HA_FULLTEXT)) + if (!force && mi_too_big_key_for_sort(key,rows)) return FALSE; } return TRUE; diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 7abf274d621..7033cd59639 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -38,12 +38,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, register uint i,j; File dfile,file; int errpos,save_errno; + myf create_flag; uint fields,length,max_key_length,packed,pointer, key_length,info_length,key_segs,options,min_key_length_skipp, base_pos,varchar_count,long_varchar_count,varchar_length, max_key_block_length,unique_key_parts,offset; ulong reclength, real_reclength,min_pack_length; - char buff[FN_REFLEN]; + char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; ulonglong tot_length,max_rows; enum en_fieldtype type; @@ -163,6 +164,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if (packed || (flags & HA_PACK_RECORD)) options|=HA_OPTION_PACK_RECORD; /* Must use packed records */ + /* We can't use checksum with static length rows */ + if (!(options & HA_OPTION_PACK_RECORD)) + options&= ~HA_OPTION_CHECKSUM; if (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) min_pack_length+=varchar_count; /* Min length to pack */ else @@ -444,7 +448,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, share.base.records=ci->max_rows; share.base.reloc= ci->reloc_rows; share.base.reclength=real_reclength; - share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);; + share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM); share.base.max_pack_length=pack_reclength; share.base.min_pack_length=min_pack_length; share.base.pack_bits=packed; @@ -467,18 +471,41 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, MI_EXTEND_BLOCK_LENGTH; if (! (flags & HA_DONT_TOUCH_DATA)) share.state.create_time= (long) time((time_t*) 0); + + if (ci->index_file_name) + { + fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4); + fn_format(linkname,name, "",MI_NAME_IEXT,4); + linkname_ptr=linkname; + /* + Don't create the table if the link or file exists to ensure that one + doesn't accidently destroy another table. + */ + create_flag=0; + } + else + { + fn_format(filename,name,"",MI_NAME_IEXT,(4+ (flags & HA_DONT_TOUCH_DATA) ? + 32 : 0)); + linkname_ptr=0; + /* Replace the current file */ + create_flag=MY_DELETE_OLD; + } - if ((file = my_create(fn_format(buff,name,"",MI_NAME_IEXT,4),0, - O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) + if ((file= my_create_with_symlink(linkname_ptr, + filename, + 0, O_RDWR | O_TRUNC, + MYF(MY_WME | create_flag))) < 0) goto err; errpos=1; - VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4)); + if (!(flags & HA_DONT_TOUCH_DATA)) { #ifdef USE_RAID if (share.base.raid_type) { - if ((dfile=my_raid_create(buff,0,O_RDWR | O_TRUNC, + (void) fn_format(filename,name,"",MI_NAME_DEXT,2+4); + if ((dfile=my_raid_create(filename,0,O_RDWR | O_TRUNC, share.base.raid_type, share.base.raid_chunks, share.base.raid_chunksize, @@ -487,9 +514,26 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, } else #endif - if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) - goto err; - + { + if (ci->data_file_name) + { + fn_format(filename, ci->data_file_name,"",MI_NAME_DEXT,4); + fn_format(linkname, name, "",MI_NAME_DEXT,4); + linkname_ptr=linkname; + create_flag=0; + } + else + { + fn_format(filename,name,"",MI_NAME_DEXT,4); + linkname_ptr=0; + create_flag=MY_DELETE_OLD; + } + if ((dfile= + my_create_with_symlink(linkname_ptr, filename, + 0,O_RDWR | O_TRUNC, + MYF(MY_WME | create_flag))) < 0) + goto err; + } errpos=3; } @@ -508,14 +552,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Write key and keyseg definitions */ for (i=0 ; i < share.base.keys - uniques; i++) { - uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; /* SerG */ + uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; if (mi_keydef_write(file, &keydefs[i])) goto err; for (j=0 ; j < keydefs[i].keysegs-ft_segs ; j++) if (mi_keyseg_write(file, &keydefs[i].seg[j])) goto err; - for (j=0 ; j < ft_segs ; j++) /* SerG */ + for (j=0 ; j < ft_segs ; j++) { MI_KEYSEG seg=ft_keysegs[j]; seg.language= keydefs[i].seg[0].language; @@ -596,20 +640,16 @@ err: VOID(my_close(dfile,MYF(0))); /* fall through */ case 2: - if (! (flags & HA_DONT_TOUCH_DATA)) - { /* QQ: Tõnu should add a call to my_raid_delete() here */ - VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4)); - my_delete(buff,MYF(0)); - } + if (! (flags & HA_DONT_TOUCH_DATA)) + my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_DEXT,2+4), + MYF(0)); /* fall through */ case 1: VOID(my_close(file,MYF(0))); if (! (flags & HA_DONT_TOUCH_DATA)) - { - VOID(fn_format(buff,name,"",MI_NAME_IEXT,2+4)); - my_delete(buff,MYF(0)); - } + my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_IEXT,2+4), + MYF(0)); } my_free((char*) rec_per_key_part, MYF(0)); DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */ diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index eda1aafecc8..8c532970dd9 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -162,7 +162,7 @@ my_bool check_table_is_closed(const char *name, const char *where) { MI_INFO *info=(MI_INFO*) pos->data; MYISAM_SHARE *share=info->s; - if (!strcmp(share->filename,filename)) + if (!strcmp(share->unique_file_name,filename)) { if (share->last_version) { diff --git a/myisam/mi_delete_all.c b/myisam/mi_delete_all.c index c3ed9455e12..2c506da865f 100644 --- a/myisam/mi_delete_all.c +++ b/myisam/mi_delete_all.c @@ -15,7 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Remove all rows from a MyISAM table */ -/* This only clears the status information; The files are not truncated */ +/* This only clears the status information and truncates the data file */ #include "myisamdef.h" @@ -50,6 +50,8 @@ int mi_delete_all_rows(MI_INFO *info) myisam_log_command(MI_LOG_DELETE_ALL,info,(byte*) 0,0,0); VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE)); + if (my_chsize(info->dfile, 0, MYF(MY_WME))) + goto err; allow_break(); /* Allow SIGHUP & SIGINT */ DBUG_RETURN(0); diff --git a/myisam/mi_delete_table.c b/myisam/mi_delete_table.c index 995106160ef..d8fff51acb6 100644 --- a/myisam/mi_delete_table.c +++ b/myisam/mi_delete_table.c @@ -50,12 +50,12 @@ int mi_delete_table(const char *name) #endif /* USE_RAID */ fn_format(from,name,"",MI_NAME_IEXT,4); - if (my_delete(from, MYF(MY_WME))) + if (my_delete_with_symlink(from, MYF(MY_WME))) DBUG_RETURN(my_errno); fn_format(from,name,"",MI_NAME_DEXT,4); #ifdef USE_RAID if (raid_type) DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME)) ? my_errno : 0); #endif - DBUG_RETURN(my_delete(from, MYF(MY_WME)) ? my_errno : 0); + DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME)) ? my_errno : 0); } diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index cf075512ac4..eb7285491ed 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -219,9 +219,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function) } if (share->state.key_map) { - share->state.key_map=0; - info->state->key_file_length=share->state.state.key_file_length= - share->base.keystart; + MI_KEYDEF *key=share->keyinfo; + uint i; + for (i=0 ; i < share->base.keys ; i++,key++) + { + if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) + { + share->state.key_map&= ~ ((ulonglong) 1 << i); + info->update|= HA_STATE_CHANGED; + } + } + if (!share->changed) { share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; @@ -237,12 +245,15 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function) } break; case HA_EXTRA_FORCE_REOPEN: + case HA_EXTRA_PREPARE_FOR_DELETE: pthread_mutex_lock(&THR_LOCK_myisam); share->last_version= 0L; /* Impossible version */ #ifdef __WIN__ /* Close the isam and data files as Win32 can't drop an open table */ pthread_mutex_lock(&share->intern_lock); - if (flush_key_blocks(share->kfile,FLUSH_RELEASE)) + if (flush_key_blocks(share->kfile, + (function == HA_EXTRA_FORCE_REOPEN ? + FLUSH_RELEASE : FLUSH_IGNORE_CHANGED))) { error=my_errno; share->changed=1; @@ -328,6 +339,24 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function) case HA_EXTRA_QUICK: info->quick_mode=1; break; + case HA_EXTRA_BULK_INSERT_BEGIN: + error=_mi_init_bulk_insert(info); + break; + case HA_EXTRA_BULK_INSERT_END: + if (info->bulk_insert) + { + uint i; + for (i=0 ; i < share->base.keys ; i++) + { + if (is_tree_inited(& info->bulk_insert[i])) + { + delete_tree(& info->bulk_insert[i]); + } + } + my_free((void *)info->bulk_insert, MYF(0)); + info->bulk_insert=0; + } + break; case HA_EXTRA_NO_ROWS: if (!share->state.header.uniques) info->opt_flag|= OPT_NO_ROWS; diff --git a/myisam/mi_info.c b/myisam/mi_info.c index 6e7abfc0914..867718de326 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -87,6 +87,8 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) x->raid_chunks= share->base.raid_chunks; x->raid_chunksize= share->base.raid_chunksize; x->key_map = share->state.key_map; + x->data_file_name = share->data_file_name; + x->index_file_name = share->index_file_name; } if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0))) x->update_time=state.st_mtime; diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index e067e80fcf3..8ef5db1d344 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -412,11 +412,14 @@ int _mi_mark_file_changed(MI_INFO *info) share->global_changed=1; share->state.open_count++; } - mi_int2store(buff,share->state.open_count); - buff[2]=1; /* Mark that it's changed */ - return (my_pwrite(share->kfile,buff,sizeof(buff), - sizeof(share->state.header), - MYF(MY_NABP))); + if (!share->temporary) + { + mi_int2store(buff,share->state.open_count); + buff[2]=1; /* Mark that it's changed */ + return (my_pwrite(share->kfile,buff,sizeof(buff), + sizeof(share->state.header), + MYF(MY_NABP))); + } } return 0; } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index de1888bc9b7..c34f2aa43f4 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -49,7 +49,7 @@ static MI_INFO *test_if_reopen(char *filename) { MI_INFO *info=(MI_INFO*) pos->data; MYISAM_SHARE *share=info->s; - if (!strcmp(share->filename,filename) && share->last_version) + if (!strcmp(share->unique_file_name,filename) && share->last_version) return info; } return 0; @@ -69,7 +69,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) int lock_error,kfile,open_mode,save_errno; uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra,keys, key_parts,unique_key_parts,tmp_length,uniques; - char name_buff[FN_REFLEN],*disk_cache,*disk_pos; + char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], + data_name[FN_REFLEN]; + char *disk_cache,*disk_pos; MI_INFO info,*m_info,*old_info; MYISAM_SHARE share_buff,*share; ulong rec_per_key_part[MI_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]; @@ -84,7 +86,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) head_length=sizeof(share_buff.state.header); bzero((byte*) &info,sizeof(info)); - VOID(fn_format(name_buff,name,"",MI_NAME_IEXT,4+16+32)); + my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0)); pthread_mutex_lock(&THR_LOCK_myisam); if (!(old_info=test_if_reopen(name_buff))) { @@ -128,6 +130,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) my_errno=HA_ERR_OLD_FILE; goto err; } + /* Don't call realpath() if the name can't be a link */ + if (strcmp(name_buff, org_name)) + (void) my_readlink(index_name, org_name, MYF(0)); + else + (void) strmov(index_name, org_name); + (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,2+4+16); + info_length=mi_uint2korr(share->state.header.header_length); base_pos=mi_uint2korr(share->state.header.base_pos); if (!(disk_cache=(char*) my_alloca(info_length))) @@ -250,7 +259,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF), &share->blobs,sizeof(MI_BLOB)*share->base.blobs, - &share->filename,strlen(name_buff)+1, + &share->unique_file_name,strlen(name_buff)+1, + &share->index_file_name,strlen(index_name)+1, + &share->data_file_name,strlen(data_name)+1, &share->state.key_root,keys*sizeof(my_off_t), &share->state.key_del, (share->state.header.max_block_size*sizeof(my_off_t)), @@ -268,7 +279,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) memcpy((char*) share->state.key_del, (char*) key_del, (sizeof(my_off_t) * share->state.header.max_block_size)); - strmov(share->filename,name_buff); + strmov(share->unique_file_name, name_buff); + strmov(share->index_file_name, index_name); + strmov(share->data_file_name, data_name); share->blocksize=min(IO_SIZE,myisam_block_size); { @@ -353,7 +366,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) lock_error=1; /* Database unlocked */ } - if (mi_open_datafile(&info, share)) + if (mi_open_datafile(&info, share, -1)) goto err; errpos=5; @@ -426,7 +439,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) my_errno=EACCES; /* Can't open in write mode */ goto err; } - if (mi_open_datafile(&info, share)) + if (mi_open_datafile(&info, share, old_info->dfile)) goto err; errpos=5; } @@ -438,12 +451,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &info.buff,(share->base.max_key_block_length*2+ share->base.max_key_length), &info.lastkey,share->base.max_key_length*3+1, - &info.filename,strlen(name)+1, + &info.filename,strlen(org_name)+1, NullS)) goto err; errpos=6; - strmov(info.filename,name); + strmov(info.filename,org_name); memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs); info.lastkey2=info.lastkey+share->base.max_key_length; @@ -461,6 +474,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->options|=HA_OPTION_READ_ONLY_DATA; info.lock_type=F_UNLCK; info.quick_mode=0; + info.bulk_insert=0; info.errkey= -1; info.page_changed=1; pthread_mutex_lock(&share->intern_lock); @@ -514,7 +528,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) pthread_mutex_unlock(&THR_LOCK_myisam); if (myisam_log_file >= 0) { - intern_filename(name_buff,share->filename); + intern_filename(name_buff,share->index_file_name); _myisam_log(MI_LOG_OPEN,m_info,name_buff,(uint) strlen(name_buff)); } DBUG_RETURN(m_info); @@ -625,15 +639,20 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo) } else if (keyinfo->flag & HA_VAR_LENGTH_KEY) { - keyinfo->bin_search=_mi_seq_search; keyinfo->get_key= _mi_get_pack_key; if (keyinfo->seg[0].flag & HA_PACK_KEY) { /* Prefix compression */ + if (!keyinfo->seg->charset || use_strcoll(keyinfo->seg->charset) || + (keyinfo->seg->flag & HA_NULL_PART)) + keyinfo->bin_search=_mi_seq_search; + else + keyinfo->bin_search=_mi_prefix_search; keyinfo->pack_key=_mi_calc_var_pack_key_length; keyinfo->store_key=_mi_store_var_pack_key; } else { + keyinfo->bin_search=_mi_seq_search; keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */ keyinfo->store_key=_mi_store_static_key; } @@ -772,14 +791,17 @@ uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead) { char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE]; - if (pRead) + if (!myisam_single_user) { - if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP))) + if (pRead) + { + if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP))) + return (MY_FILE_ERROR); + } + else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) return (MY_FILE_ERROR); + mi_state_info_read(buff, state); } - else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) - return (MY_FILE_ERROR); - mi_state_info_read(buff, state); return 0; } @@ -987,37 +1009,37 @@ char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo) } /************************************************************************** - ** Help functions for recover - *************************************************************************/ +Open data file with or without RAID +We can't use dup() here as the data file descriptors need to have different +active seek-positions. -int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share) -{ - char name_buff[FN_REFLEN]; - (void) fn_format(name_buff, share->filename,"",MI_NAME_DEXT, 2+4); +The argument file_to_dup is here for the future if there would on some OS +exist a dup()-like call that would give us two different file descriptors. +*************************************************************************/ +int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused))) +{ #ifdef USE_RAID if (share->base.raid_type) { - if ((info->dfile=my_raid_open(name_buff, - share->mode | O_SHARE, - share->base.raid_type, - share->base.raid_chunks, - share->base.raid_chunksize, - MYF(MY_WME | MY_RAID))) < 0) - return 1; + info->dfile=my_raid_open(share->data_file_name, + share->mode | O_SHARE, + share->base.raid_type, + share->base.raid_chunks, + share->base.raid_chunksize, + MYF(MY_WME | MY_RAID)); } else #endif - if ((info->dfile=my_open(name_buff, share->mode | O_SHARE, - MYF(MY_WME))) < 0) - return 1; - return 0; + info->dfile=my_open(share->data_file_name, share->mode | O_SHARE, + MYF(MY_WME)); + return info->dfile >= 0 ? 0 : 1; } int mi_open_keyfile(MYISAM_SHARE *share) { - if ((share->kfile=my_open(share->filename, share->mode | O_SHARE, + if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE, MYF(MY_WME))) < 0) return 1; return 0; diff --git a/myisam/mi_rename.c b/myisam/mi_rename.c index 5c92db3f7ce..4d6250f58f4 100644 --- a/myisam/mi_rename.c +++ b/myisam/mi_rename.c @@ -51,7 +51,7 @@ int mi_rename(const char *old_name, const char *new_name) fn_format(from,old_name,"",MI_NAME_IEXT,4); fn_format(to,new_name,"",MI_NAME_IEXT,4); - if (my_rename(from, to, MYF(MY_WME))) + if (my_rename_with_symlink(from, to, MYF(MY_WME))) DBUG_RETURN(my_errno); fn_format(from,old_name,"",MI_NAME_DEXT,4); fn_format(to,new_name,"",MI_NAME_DEXT,4); @@ -60,5 +60,5 @@ int mi_rename(const char *old_name, const char *new_name) DBUG_RETURN(my_raid_rename(from, to, raid_chunks, MYF(MY_WME)) ? my_errno : 0); #endif - DBUG_RETURN(my_rename(from, to,MYF(MY_WME)) ? my_errno : 0); + DBUG_RETURN(my_rename_with_symlink(from, to,MYF(MY_WME)) ? my_errno : 0); } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2c04679ed4c..b9895e9d6cd 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -22,26 +22,26 @@ #define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1) static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, - uint *return_key_length); + uchar *key, uchar *keypos, + uint *return_key_length); - /* Check index */ + /* Check index */ int _mi_check_index(MI_INFO *info, int inx) { - if (inx == -1) /* Use last index */ + if (inx == -1) /* Use last index */ inx=info->lastinx; if (inx < 0 || ! (((ulonglong) 1 << inx) & info->s->state.key_map)) { my_errno=HA_ERR_WRONG_INDEX; return -1; } - if (info->lastinx != inx) /* Index changed */ + if (info->lastinx != inx) /* Index changed */ { info->lastinx = inx; info->page_changed=1; info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) | - HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); + HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); } if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache)) return(-1); @@ -49,15 +49,15 @@ int _mi_check_index(MI_INFO *info, int inx) } /* mi_check_index */ - /* - ** Search after row by a key - ** Position to row is stored in info->lastpos - ** Return: -1 if not found - ** 1 if one should continue search on higher level - */ + /* + ** Search after row by a key + ** Position to row is stored in info->lastpos + ** Return: -1 if not found + ** 1 if one should continue search on higher level + */ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, - uchar *key, uint key_len, uint nextflag, register my_off_t pos) + uchar *key, uint key_len, uint nextflag, register my_off_t pos) { my_bool last_key; int error,flag; @@ -66,25 +66,25 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar lastkey[MI_MAX_KEY_BUFF],*buff; DBUG_ENTER("_mi_search"); DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld", - pos,nextflag,info->lastpos)); + pos,nextflag,info->lastpos)); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len);); if (pos == HA_OFFSET_ERROR) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ info->lastpos= HA_OFFSET_ERROR; if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST))) - DBUG_RETURN(-1); /* Not found ; return error */ - DBUG_RETURN(1); /* Search at upper levels */ + DBUG_RETURN(-1); /* Not found ; return error */ + DBUG_RETURN(1); /* Search at upper levels */ } if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff, - test(!(nextflag & SEARCH_SAVE_BUFF))))) + test(!(nextflag & SEARCH_SAVE_BUFF))))) goto err; DBUG_DUMP("page",(byte*) buff,mi_getint(buff)); flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag, - &keypos,lastkey, &last_key); + &keypos,lastkey, &last_key); if (flag == MI_FOUND_WRONG_KEY) DBUG_RETURN(-1); nod_flag=mi_test_if_nod(buff); @@ -93,35 +93,35 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (flag) { if ((error=_mi_search(info,keyinfo,key,key_len,nextflag, - _mi_kpos(nod_flag,keypos))) <= 0) + _mi_kpos(nod_flag,keypos))) <= 0) DBUG_RETURN(error); if (flag >0) { if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) && - keypos == buff+2+nod_flag) - DBUG_RETURN(1); /* Bigger than key */ + keypos == buff+2+nod_flag) + DBUG_RETURN(1); /* Bigger than key */ } else if (nextflag & SEARCH_BIGGER && keypos >= maxpos) - DBUG_RETURN(1); /* Smaller than key */ + DBUG_RETURN(1); /* Smaller than key */ } else { if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME) - || key_len) && nod_flag) + || key_len) && nod_flag) { if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND, - _mi_kpos(nod_flag,keypos))) >= 0 || - my_errno != HA_ERR_KEY_NOT_FOUND) - DBUG_RETURN(error); - info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */ + _mi_kpos(nod_flag,keypos))) >= 0 || + my_errno != HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(error); + info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */ } } if (pos != info->last_keypage) { uchar *old_buff=buff; if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff, - test(!(nextflag & SEARCH_SAVE_BUFF))))) + test(!(nextflag & SEARCH_SAVE_BUFF))))) goto err; keypos=buff+(keypos-old_buff); maxpos=buff+(maxpos-old_buff); @@ -131,13 +131,13 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, { uint not_used; if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos, - &info->lastkey_length)) + &info->lastkey_length)) goto err; if ((nextflag & SEARCH_LAST) && - _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, - ¬_used)) + _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, + ¬_used)) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ goto err; } } @@ -156,7 +156,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, info->int_keytree_version=keyinfo->version; info->last_search_keypage=info->last_keypage; info->page_changed=0; - info->buff_used= (info->buff != buff); /* If we have to reread buff */ + info->buff_used= (info->buff != buff); /* If we have to reread buff */ DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos)); DBUG_RETURN(0); @@ -168,14 +168,14 @@ err: } /* _mi_search */ - /* Search after key in page-block */ - /* If packed key puts smaller or identical key in buff */ - /* ret_pos point to where find or bigger key starts */ - /* ARGSUSED */ + /* Search after key in page-block */ + /* If packed key puts smaller or identical key in buff */ + /* ret_pos point to where find or bigger key starts */ + /* ARGSUSED */ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, - uchar *buff __attribute__((unused)), my_bool *last_key) + uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, + uchar *buff __attribute__((unused)), my_bool *last_key) { reg4 int start,mid,end,save_end; int flag; @@ -193,17 +193,17 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { mid= (start+end)/2; if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len, - comp_flag,¬_used)) - >= 0) + comp_flag,¬_used)) + >= 0) end=mid; else start=mid+1; } if (mid != start) flag=_mi_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len, - comp_flag,¬_used); + comp_flag,¬_used); if (flag < 0) - start++; /* point at next, bigger key */ + start++; /* point at next, bigger key */ *ret_pos=page+(uint) start*totlength; *last_key= end == save_end; DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start)); @@ -211,13 +211,13 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, } /* _mi_bin_search */ - /* Used instead of _mi_bin_search() when key is packed */ - /* Puts smaller or identical key in buff */ - /* Key is searched sequentially */ + /* Used instead of _mi_bin_search() when key is packed */ + /* Puts smaller or identical key in buff */ + /* Key is searched sequentially */ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, - uchar *buff, my_bool *last_key) + uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, + uchar *buff, my_bool *last_key) { int flag; uint nod_flag,length,not_used; @@ -229,7 +229,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, nod_flag=mi_test_if_nod(page); page+=2+nod_flag; *ret_pos=page; - t_buff[0]=0; /* Avoid bugs */ + t_buff[0]=0; /* Avoid bugs */ while (page < end) { length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff); @@ -237,11 +237,11 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx", - length,page,end)); + length,page,end)); DBUG_RETURN(MI_FOUND_WRONG_KEY); } if ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag, - ¬_used)) >= 0) + ¬_used)) >= 0) break; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag)); @@ -250,14 +250,226 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, *ret_pos=page; } if (flag == 0) - memcpy(buff,t_buff,length); /* Result is first key */ + memcpy(buff,t_buff,length); /* Result is first key */ *last_key= page == end; DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos)); DBUG_RETURN(flag); } /* _mi_seq_search */ - /* Get pos to a key_block */ +int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, + uchar *key, uint key_len, uint nextflag, uchar **ret_pos, + uchar *buff, my_bool *last_key) +{ + /* my_flag is raw comparison result to be changed according to + SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. + flag is the value returned by _mi_key_cmp and as treated as final */ + int flag=0, my_flag=-1; + uint nod_flag, length, len, matched, cmplen, kseg_len; + uint prefix_len,suffix_len; + int key_len_skip, seg_len_pack, key_len_left; + uchar *end, *kseg, *vseg; + uchar *sort_order=keyinfo->seg->charset->sort_order; + uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2; + uchar *saved_from, *saved_to, *saved_vseg; + uint saved_length=0, saved_prefix_len=0; + DBUG_ENTER("_mi_prefix_search"); + + LINT_INIT(length); + LINT_INIT(prefix_len); + LINT_INIT(seg_len_pack); + LINT_INIT(saved_from); + LINT_INIT(saved_to); + LINT_INIT(saved_vseg); + + t_buff[0]=0; /* Avoid bugs */ + if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) + key_len=USE_WHOLE_KEY; + end= page+mi_getint(page); + nod_flag=mi_test_if_nod(page); + page+=2+nod_flag; + *ret_pos=page; + kseg=key; + { + uint lenght_pack; + get_key_pack_length(kseg_len,lenght_pack,kseg); + key_len_skip=lenght_pack+kseg_len; + key_len_left=(int) key_len- (int) key_len_skip; + cmplen=(key_len_left>=0) ? kseg_len : key_len-lenght_pack; + DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg)); + } + +/* + Keys are compressed the following way: + + If the max length of first key segment <= 127 characters the prefix is + 1 byte else it's 2 byte + + prefix The high bit is set if this is a prefix for the prev key + length Packed length if the previous was a prefix byte + [length] Length character of data + next-key-seg Next key segments +*/ + + matched=0; /* how many char's from prefix were alredy matched */ + len=0; /* length of previous key unpacked */ + + while (page < end) + { + uint packed= *page & 128; + + vseg=page; + if (keyinfo->seg->length >= 127) + { + suffix_len=mi_uint2korr(vseg) & 32767; + vseg+=2; + } + else + suffix_len= *vseg++ & 127; + + if (packed) + { + if (suffix_len == 0) /* Same key */ + prefix_len=len; + else + { + prefix_len=suffix_len; + get_key_length(suffix_len,vseg); + } + } + else + prefix_len=0; + + len=prefix_len+suffix_len; + seg_len_pack=get_pack_length(len); + t_buff=tt_buff+3-seg_len_pack; + store_key_length(t_buff,len); + + if (prefix_len > saved_prefix_len) + memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg, + prefix_len-saved_prefix_len); + saved_vseg=vseg; + saved_prefix_len=prefix_len; + + DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg)); + { + uchar *from=vseg+suffix_len; + MI_KEYSEG *keyseg; + uint l; + + for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ ) + { + + if (keyseg->flag & HA_NULL_PART) + { + if (!(*from++)) + continue; + } + if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + { + get_key_length(l,from); + } + else + l=keyseg->length; + + from+=l; + } + from+=keyseg->length; + page=from+nod_flag; + length=from-vseg; + } + + if (page > end) + { + my_errno=HA_ERR_CRASHED; + DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx", + length,page,end)); + DBUG_RETURN(MI_FOUND_WRONG_KEY); + } + + if (matched >= prefix_len) + { + /* We have to compare. But we can still skip part of the key */ + uint left; + uchar *k=kseg+prefix_len; + + left=(len>cmplen) ? cmplen-prefix_len : suffix_len; + + matched=prefix_len+left; + + for(my_flag=0;left;left--) + if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++])) + break; + + if (my_flag>0) /* mismatch */ + break; + else if (my_flag==0) /* match */ + { /* + ** len cmplen seg_left_len more_segs + ** < matched=len; continue search + ** > = prefix ? found : (matched=len; continue search) + ** > < - ok, found + ** = < - ok, found + ** = = - ok, found + ** = = + next seg + */ + if (len < cmplen) + { + my_flag= -1; + } + else if (len > cmplen) + { + if ((my_flag= (!(nextflag & SEARCH_PREFIX) || key_len_left>0))) + break; + goto fix_flag; + } + else if (key_len_left>0) + { + uint not_used; + if ((flag = _mi_key_cmp(keyinfo->seg+1,vseg, + k,key_len_left,nextflag,¬_used)) >= 0) + break; + } + else + { + /* at this line flag==-1 if the following lines were already + visited and 0 otherwise, i.e. flag <=0 here always !!! */ + fix_flag: + if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) + flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1; + if (flag>=0) break; + } + } + matched-=left; + } + /* else (matched < prefix_len) ---> do nothing. */ + + memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len); + saved_to=buff+saved_length; + saved_from=saved_vseg; + saved_length=length; + *ret_pos=page; + } + if (my_flag) + flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag; + if (flag == 0) + { + memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len); + saved_to=buff+saved_length; + saved_from=saved_vseg; + saved_length=length; + } + if (saved_length) + memcpy(saved_to,saved_from,saved_length); + + *last_key= page == end; + + DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos)); + DBUG_RETURN(flag); +} /* _mi_prefix_search */ + + + /* Get pos to a key_block */ my_off_t _mi_kpos(uint nod_flag, uchar *after_key) { @@ -286,14 +498,14 @@ my_off_t _mi_kpos(uint nod_flag, uchar *after_key) return (my_off_t) (mi_uint2korr(after_key)*MI_KEY_BLOCK_LENGTH); case 1: return (uint) (*after_key)*MI_KEY_BLOCK_LENGTH; - case 0: /* At leaf page */ - default: /* Impossible */ + case 0: /* At leaf page */ + default: /* Impossible */ return(HA_OFFSET_ERROR); } } /* _kpos */ - /* Save pos to a key_block */ + /* Save pos to a key_block */ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos) { @@ -315,12 +527,12 @@ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos) case 3: mi_int3store(buff,pos); break; case 2: mi_int2store(buff,(uint) pos); break; case 1: buff[0]= (uchar) pos; break; - default: abort(); /* impossible */ + default: abort(); /* impossible */ } } /* _mi_kpointer */ - /* Calc pos to a data-record from a key */ + /* Calc pos to a data-record from a key */ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key) @@ -335,19 +547,19 @@ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key) case 5: pos= (my_off_t) mi_uint5korr(after_key); break; #else case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break; - case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break; - case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break; - case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break; + case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break; + case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break; + case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break; #endif case 4: pos= (my_off_t) mi_uint4korr(after_key); break; case 3: pos= (my_off_t) mi_uint3korr(after_key); break; case 2: pos= (my_off_t) mi_uint2korr(after_key); break; default: - pos=0L; /* Shut compiler up */ + pos=0L; /* Shut compiler up */ } return (info->s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : - pos*info->s->base.pack_reclength; + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : + pos*info->s->base.pack_reclength; } @@ -361,22 +573,22 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr) case 8: pos= (my_off_t) mi_uint8korr(ptr); if (pos == HA_OFFSET_ERROR) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 7: pos= (my_off_t) mi_uint7korr(ptr); if (pos == (((my_off_t) 1) << 56) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 6: pos= (my_off_t) mi_uint6korr(ptr); if (pos == (((my_off_t) 1) << 48) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 5: pos= (my_off_t) mi_uint5korr(ptr); if (pos == (((my_off_t) 1) << 40) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; #else case 8: @@ -401,20 +613,20 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr) if (pos == (my_off_t) (1 << 16) -1) return HA_OFFSET_ERROR; break; - default: abort(); /* Impossible */ + default: abort(); /* Impossible */ } return ((s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : - pos*s->base.pack_reclength); + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : + pos*s->base.pack_reclength); } - /* save position to record */ + /* save position to record */ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos) { if (!(info->s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) && + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) && pos != HA_OFFSET_ERROR) pos/=info->s->base.pack_reclength; @@ -437,27 +649,27 @@ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos) case 4: mi_int4store(buff,pos); break; case 3: mi_int3store(buff,pos); break; case 2: mi_int2store(buff,(uint) pos); break; - default: abort(); /* Impossible */ + default: abort(); /* Impossible */ } } /* _mi_dpointer */ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length, - uchar *b, uint b_length, my_bool part_key) + uchar *b, uint b_length, my_bool part_key) { - uint length= min(a_length,b_length); - uchar *end= a+ length; int flag; #ifdef USE_STRCOLL if (use_strcoll(charset_info)) { - if ((flag = my_strnncoll(charset_info, a, a_length, b, b_length))) - return flag; + /* QQ: This needs to work with part keys at some point */ + return my_strnncoll(charset_info, a, a_length, b, b_length); } else #endif { + uint length= min(a_length,b_length); + uchar *end= a+ length; uchar *sort_order=charset_info->sort_order; while (a < end) if ((flag= (int) sort_order[*a++] - (int) sort_order[*b++])) @@ -470,7 +682,7 @@ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length, static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, - my_bool part_key) + my_bool part_key) { uint length= min(a_length,b_length); uchar *end= a+ length; @@ -485,19 +697,19 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, } - /* - ** Compare two keys with is bigger - ** Returns <0, 0, >0 acording to with is bigger - ** Key_length specifies length of key to use. Number-keys can't - ** be splited - ** If flag <> SEARCH_FIND compare also position - */ + /* + ** Compare two keys + ** Returns <0, 0, >0 acording to which is bigger + ** Key_length specifies length of key to use. Number-keys can't + ** be splited + ** If flag <> SEARCH_FIND compare also position + */ #define FCMP(A,B) ((int) (A) - (int) (B)) int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, - register uchar *b, uint key_length, uint nextflag, - uint *diff_pos) + register uchar *b, uint key_length, uint nextflag, + uint *diff_pos) { int flag; int16 s_1,s_2; @@ -522,106 +734,113 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, key_length--; if (*a != *b) { - flag = (int) *a - (int) *b; - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + flag = (int) *a - (int) *b; + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); } b++; - if (!*a++) /* If key was NULL */ + if (!*a++) /* If key was NULL */ { - if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) - nextflag=SEARCH_SAME; /* Allow duplicate keys */ - next_key_length=key_length; - continue; /* To next key part */ + if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) + nextflag=SEARCH_SAME; /* Allow duplicate keys */ + next_key_length=key_length; + continue; /* To next key part */ } } end= a+ min(keyseg->length,key_length); next_key_length=key_length-keyseg->length; switch ((enum ha_base_keytype) keyseg->type) { - case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ if (keyseg->flag & HA_SPACE_PACK) { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } else { - uint length=(uint) (end-a); - if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a=end; - b+=length; + uint length=(uint) (end-a), a_length=length, b_length=length; + if (!(nextflag & SEARCH_PREFIX)) + { + while (a_length && a[a_length-1] == ' ') + a_length--; + while (b_length && b[b_length-1] == ' ') + b_length--; + } + if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a=end; + b+=length; } break; case HA_KEYTYPE_BINARY: if (keyseg->flag & HA_SPACE_PACK) { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=compare_bin(a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } else { - uint length=keyseg->length; - if ((flag=compare_bin(a,length,b,length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=length; - b+=length; + uint length=keyseg->length; + if ((flag=compare_bin(a,length,b,length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=length; + b+=length; } break; case HA_KEYTYPE_VARTEXT: { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } break; case HA_KEYTYPE_VARBINARY: { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=compare_bin(a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } break; case HA_KEYTYPE_INT8: @@ -629,7 +848,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, int i_1= (int) *((signed char*) a); int i_2= (int) *((signed char*) b); if ((flag = CMP(i_1,i_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b++; break; @@ -638,26 +857,26 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, s_1= mi_sint2korr(a); s_2= mi_sint2korr(b); if ((flag = CMP(s_1,s_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 2; /* sizeof(short int); */ break; case HA_KEYTYPE_USHORT_INT: { - uint16 us_1,us_2; - us_1= mi_sint2korr(a); - us_2= mi_sint2korr(b); - if ((flag = CMP(us_1,us_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+=2; /* sizeof(short int); */ - break; + uint16 us_1,us_2; + us_1= mi_sint2korr(a); + us_2= mi_sint2korr(b); + if ((flag = CMP(us_1,us_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a= end; + b+=2; /* sizeof(short int); */ + break; } case HA_KEYTYPE_LONG_INT: l_1= mi_sint4korr(a); l_2= mi_sint4korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ break; @@ -665,7 +884,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, u_1= mi_sint4korr(a); u_2= mi_sint4korr(b); if ((flag = CMP(u_1,u_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ break; @@ -673,7 +892,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, l_1=mi_sint3korr(a); l_2=mi_sint3korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; break; @@ -681,7 +900,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, l_1=mi_uint3korr(a); l_2=mi_uint3korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; break; @@ -689,7 +908,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, mi_float4get(f_1,a); mi_float4get(f_2,b); if ((flag = CMP(f_1,f_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(float); */ break; @@ -697,65 +916,65 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, mi_float8get(d_1,a); mi_float8get(d_2,b); if ((flag = CMP(d_1,d_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; /* sizeof(double); */ break; - case HA_KEYTYPE_NUM: /* Numeric key */ + case HA_KEYTYPE_NUM: /* Numeric key */ { int swap_flag= 0; int alength,blength; if (keyseg->flag & HA_REVERSE_SORT) { - swap(uchar*,a,b); - swap_flag=1; /* Remember swap of a & b */ + swap(uchar*,a,b); + swap_flag=1; /* Remember swap of a & b */ end= a+ (int) (end-b); } if (keyseg->flag & HA_SPACE_PACK) { - alength= *a++; blength= *b++; - end=a+alength; - next_key_length=key_length-blength-1; + alength= *a++; blength= *b++; + end=a+alength; + next_key_length=key_length-blength-1; } else { - alength= (int) (end-a); - blength=keyseg->length; - /* remove pre space from keys */ - for ( ; alength && *a == ' ' ; a++, alength--) ; - for ( ; blength && *b == ' ' ; b++, blength--) ; + alength= (int) (end-a); + blength=keyseg->length; + /* remove pre space from keys */ + for ( ; alength && *a == ' ' ; a++, alength--) ; + for ( ; blength && *b == ' ' ; b++, blength--) ; } if (*a == '-') { - if (*b != '-') - return -1; - a++; b++; - swap(uchar*,a,b); - swap(int,alength,blength); - swap_flag=1-swap_flag; - alength--; blength--; - end=a+alength; + if (*b != '-') + return -1; + a++; b++; + swap(uchar*,a,b); + swap(int,alength,blength); + swap_flag=1-swap_flag; + alength--; blength--; + end=a+alength; } else if (*b == '-') - return 1; + return 1; while (alength && (*a == '+' || *a == '0')) { - a++; alength--; + a++; alength--; } while (blength && (*b == '+' || *b == '0')) { - b++; blength--; + b++; blength--; } if (alength != blength) - return (alength < blength) ? -1 : 1; + return (alength < blength) ? -1 : 1; while (a < end) - if (*a++ != *b++) - return ((int) a[-1] - (int) b[-1]); + if (*a++ != *b++) + return ((int) a[-1] - (int) b[-1]); - if (swap_flag) /* Restore pointers */ - swap(uchar*,a,b); + if (swap_flag) /* Restore pointers */ + swap(uchar*,a,b); break; } #ifdef HAVE_LONG_LONG @@ -765,7 +984,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, ll_a= mi_sint8korr(a); ll_b= mi_sint8korr(b); if ((flag = CMP(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; break; @@ -776,14 +995,14 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, ll_a= mi_uint8korr(a); ll_b= mi_uint8korr(b); if ((flag = CMP(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; break; } #endif - case HA_KEYTYPE_END: /* Ready */ - goto end; /* diff_pos is incremented */ + case HA_KEYTYPE_END: /* Ready */ + goto end; /* diff_pos is incremented */ } } (*diff_pos)++; @@ -798,33 +1017,33 @@ end: { if (*a++ != *b++) { - flag= FCMP(a[-1],b[-1]); - break; + flag= FCMP(a[-1],b[-1]); + break; } } if (nextflag & SEARCH_SAME) - return (flag); /* read same */ + return (flag); /* read same */ if (nextflag & SEARCH_BIGGER) - return (flag <= 0 ? -1 : 1); /* read next */ - return (flag < 0 ? -1 : 1); /* read previous */ + return (flag <= 0 ? -1 : 1); /* read next */ + return (flag < 0 ? -1 : 1); /* read previous */ } return 0; } /* _mi_key_cmp */ - /* Get key from key-block */ - /* page points at previous key; its advanced to point at next key */ - /* key should contain previous key */ - /* Returns length of found key + pointers */ - /* nod_flag is a flag if we are on nod */ + /* Get key from key-block */ + /* page points at previous key; its advanced to point at next key */ + /* key should contain previous key */ + /* Returns length of found key + pointers */ + /* nod_flag is a flag if we are on nod */ - /* same as _mi_get_key but used with fixed length keys */ + /* same as _mi_get_key but used with fixed length keys */ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page, register uchar *key) + register uchar **page, register uchar *key) { memcpy((byte*) key,(byte*) *page, - (size_t) (keyinfo->keylength+nod_flag)); + (size_t) (keyinfo->keylength+nod_flag)); *page+=keyinfo->keylength+nod_flag; return(keyinfo->keylength); } /* _mi_get_static_key */ @@ -833,7 +1052,7 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, /* Key with is packed against previous key or key with a NULL column */ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page_pos, register uchar *key) + register uchar **page_pos, register uchar *key) { reg1 MI_KEYSEG *keyseg; uchar *start_key,*page=*page_pos; @@ -849,11 +1068,11 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, uint packed= *page & 128,tot_length,rest_length; if (keyseg->length >= 127) { - length=mi_uint2korr(page) & 32767; - page+=2; + length=mi_uint2korr(page) & 32767; + page+=2; } else - length= *page++ & 127; + length= *page++ & 127; if (packed) { @@ -914,23 +1133,23 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, } else { - if (keyseg->flag & HA_NULL_PART) - { - if (!length--) /* Null part */ - { - *key++=0; - continue; - } - *key++=1; /* Not null */ - } + if (keyseg->flag & HA_NULL_PART) + { + if (!length--) /* Null part */ + { + *key++=0; + continue; + } + *key++=1; /* Not null */ + } } if (length > (uint) keyseg->length) { - DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx", - length, keyseg->length, *page_pos)); - DBUG_DUMP("key",(char*) *page_pos,16); - my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx", + length, keyseg->length, *page_pos)); + DBUG_DUMP("key",(char*) *page_pos,16); + my_errno=HA_ERR_CRASHED; + return 0; /* Error */ } store_key_length_inc(key,length); } @@ -938,18 +1157,18 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { if (keyseg->flag & HA_NULL_PART) { - if (!(*key++ = *page++)) - continue; + if (!(*key++ = *page++)) + continue; } if (keyseg->flag & - (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) { - uchar *tmp=page; - get_key_length(length,tmp); - length+=(uint) (tmp-page); + uchar *tmp=page; + get_key_length(length,tmp); + length+=(uint) (tmp-page); } else - length=keyseg->length; + length=keyseg->length; } memcpy((byte*) key,(byte*) page,(size_t) length); key+=length; @@ -966,7 +1185,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, /* key that is packed relatively to previous */ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page_pos, register uchar *key) + register uchar **page_pos, register uchar *key) { reg1 MI_KEYSEG *keyseg; uchar *start_key,*page=*page_pos,*page_end,*from,*from_end; @@ -981,16 +1200,16 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (length > keyinfo->maxlength) { DBUG_PRINT("error",("Found too long binary packed key: %d of %d at %lx", - length, keyinfo->maxlength, *page_pos)); + length, keyinfo->maxlength, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); my_errno=HA_ERR_CRASHED; - return 0; /* Wrong key */ + return 0; /* Wrong key */ } from=key; from_end=key+length; } else { - from=page; from_end=page_end; /* Not packed key */ + from=page; from_end=page_end; /* Not packed key */ } /* @@ -1004,7 +1223,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { if (from == from_end) { from=page; from_end=page_end; } if (!(*key++ = *from++)) - continue; /* Null part */ + continue; /* Null part */ } if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) { @@ -1012,10 +1231,10 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (from == from_end) { from=page; from_end=page_end; } if ((length= (*key++ = *from++)) == 255) { - if (from == from_end) { from=page; from_end=page_end; } - length= (uint) ((*key++ = *from++)) << 8; - if (from == from_end) { from=page; from_end=page_end; } - length+= (uint) ((*key++ = *from++)); + if (from == from_end) { from=page; from_end=page_end; } + length= (uint) ((*key++ = *from++)) << 8; + if (from == from_end) { from=page; from_end=page_end; } + length+= (uint) ((*key++ = *from++)); } } else @@ -1023,7 +1242,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if ((tmp=(uint) (from_end-from)) <= length) { - key+=tmp; /* Use old key */ + key+=tmp; /* Use old key */ length-=tmp; from=page; from_end=page_end; } @@ -1034,7 +1253,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, length=keyseg->length+nod_flag; if ((tmp=(uint) (from_end-from)) <= length) { - memcpy(key+tmp,page,length-tmp); /* Get last part of key */ + memcpy(key+tmp,page,length-tmp); /* Get last part of key */ *page_pos= page+length-tmp; } else @@ -1043,7 +1262,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { DBUG_PRINT("error",("Error when unpacking key")); my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + return 0; /* Error */ } memcpy((byte*) key,(byte*) from,(size_t) length); *page_pos= from+length; @@ -1052,11 +1271,11 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, } - /* Get key at position without knowledge of previous key */ - /* Returns pointer to next key */ + /* Get key at position without knowledge of previous key */ + /* Returns pointer to next key */ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, uint *return_key_length) + uchar *key, uchar *keypos, uint *return_key_length) { uint nod_flag; DBUG_ENTER("_mi_get_key"); @@ -1070,14 +1289,14 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, else { page+=2+nod_flag; - key[0]=0; /* safety */ + key[0]=0; /* safety */ while (page <= keypos) { *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(0); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(0); } } } @@ -1086,12 +1305,12 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, } /* _mi_get_key */ - /* Get key at position without knowledge of previous key */ - /* Returns 0 if ok */ + /* Get key at position without knowledge of previous key */ + /* Returns 0 if ok */ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, - uint *return_key_length) + uchar *key, uchar *keypos, + uint *return_key_length) { uint nod_flag; DBUG_ENTER("_mi_get_prev_key"); @@ -1101,20 +1320,20 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, { *return_key_length=keyinfo->keylength; bmove((byte*) key,(byte*) keypos- *return_key_length-nod_flag, - *return_key_length); + *return_key_length); DBUG_RETURN(0); } else { page+=2+nod_flag; - key[0]=0; /* safety */ + key[0]=0; /* safety */ while (page < keypos) { *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(1); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(1); } } } @@ -1123,11 +1342,11 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - /* Get last key from key-page */ - /* Return pointer to where key starts */ + /* Get last key from key-page */ + /* Return pointer to where key starts */ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *lastkey, uchar *endpos, uint *return_key_length) + uchar *lastkey, uchar *endpos, uint *return_key_length) { uint nod_flag; uchar *lastpos; @@ -1152,9 +1371,9 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey); if (*return_key_length == 0) { - DBUG_PRINT("error",("Couldn't find last key: page: %lx",page)); - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(0); + DBUG_PRINT("error",("Couldn't find last key: page: %lx",page)); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(0); } } } @@ -1163,7 +1382,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, } /* _mi_get_last_key */ - /* Calculate length of key */ + /* Calculate length of key */ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) { @@ -1178,7 +1397,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) { if (keyseg->flag & HA_NULL_PART) if (!*key++) - continue; + continue; if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH)) { uint length; @@ -1192,28 +1411,28 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) } /* _mi_keylength */ - /* Move a key */ + /* Move a key */ uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from) { reg1 uint length; memcpy((byte*) to, (byte*) from, - (size_t) (length=_mi_keylength(keyinfo,from))); + (size_t) (length=_mi_keylength(keyinfo,from))); return to+length; } - /* Find next/previous record with same key */ - /* This can't be used when database is touched after last read */ + /* Find next/previous record with same key */ + /* This can't be used when database is touched after last read */ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, - uchar *key, uint key_length, uint nextflag, my_off_t pos) + uchar *key, uint key_length, uint nextflag, my_off_t pos) { int error; uint nod_flag; uchar lastkey[MI_MAX_KEY_BUFF]; DBUG_ENTER("_mi_search_next"); DBUG_PRINT("enter",("nextflag: %d lastpos: %ld int_keypos: %lx", - nextflag,(long) info->lastpos,info->int_keypos)); + nextflag,(long) info->lastpos,info->int_keypos)); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length);); /* Force full read if we are at last key or if we are not on a leaf @@ -1228,12 +1447,12 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, (info->int_keytree_version != keyinfo->version && (info->int_nod_flag || info->buff_used))) DBUG_RETURN(_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, pos)); + nextflag | SEARCH_SAVE_BUFF, pos)); if (info->buff_used) { if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage, - info->buff,0)) + info->buff,0)) DBUG_RETURN(-1); info->buff_used=0; } @@ -1242,36 +1461,36 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, nod_flag=mi_test_if_nod(info->buff); memcpy(lastkey,key,key_length); - if (nextflag & SEARCH_BIGGER) /* Next key */ + if (nextflag & SEARCH_BIGGER) /* Next key */ { my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos); if (tmp_pos != HA_OFFSET_ERROR) { if ((error=_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0) - DBUG_RETURN(error); + nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0) + DBUG_RETURN(error); } if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag, - &info->int_keypos,lastkey))) + &info->int_keypos,lastkey))) DBUG_RETURN(-1); } - else /* Previous key */ + else /* Previous key */ { uint length; /* Find start of previous key */ info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey, - info->int_keypos, &length); + info->int_keypos, &length); if (!info->int_keypos) DBUG_RETURN(-1); if (info->int_keypos == info->buff+2) DBUG_RETURN(_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, pos)); + nextflag | SEARCH_SAVE_BUFF, pos)); if ((error=_mi_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF, - _mi_kpos(nod_flag,info->int_keypos))) <= 0) + _mi_kpos(nod_flag,info->int_keypos))) <= 0) DBUG_RETURN(error); if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey, - info->int_keypos,&info->lastkey_length)) + info->int_keypos,&info->lastkey_length)) DBUG_RETURN(-1); } memcpy(info->lastkey,lastkey,info->lastkey_length); @@ -1281,11 +1500,11 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, } /* _mi_search_next */ - /* Search after position for the first row in an index */ - /* This is stored in info->lastpos */ + /* Search after position for the first row in an index */ + /* This is stored in info->lastpos */ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, - register my_off_t pos) + register my_off_t pos) { uint nod_flag; uchar *page; @@ -1310,7 +1529,7 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, - info->lastkey); + info->lastkey); info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1; info->int_nod_flag=nod_flag; info->int_keytree_version=keyinfo->version; @@ -1323,11 +1542,11 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, } /* _mi_search_first */ - /* Search after position for the last row in an index */ - /* This is stored in info->lastpos */ + /* Search after position for the last row in an index */ + /* This is stored in info->lastpos */ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, - register my_off_t pos) + register my_off_t pos) { uint nod_flag; uchar *buff,*page; @@ -1335,7 +1554,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (pos == HA_OFFSET_ERROR) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ info->lastpos= HA_OFFSET_ERROR; DBUG_RETURN(-1); } @@ -1353,7 +1572,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page, - &info->lastkey_length)) + &info->lastkey_length)) DBUG_RETURN(-1); info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length); info->int_keypos=info->int_maxpos=page; @@ -1373,22 +1592,22 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, ** Functions to store and pack a key in a page ** ** mi_calc_xx_key_length takes the following arguments: -** nod_flag If nod: Length of nod-pointer -** next_key Position to pos after the new key in buffer -** org_key Key that was before the next key in buffer -** prev_key Last key before current key -** key Key that will be stored -** s_temp Information how next key will be packed +** nod_flag If nod: Length of nod-pointer +** next_key Position to pos after the new key in buffer +** org_key Key that was before the next key in buffer +** prev_key Last key before current key +** key Key that will be stored +** s_temp Information how next key will be packed ****************************************************************************/ /* Static length key */ int _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag, - uchar *next_pos __attribute__((unused)), - uchar *org_key __attribute__((unused)), - uchar *prev_key __attribute__((unused)), - uchar *key, MI_KEY_PARAM *s_temp) + uchar *next_pos __attribute__((unused)), + uchar *org_key __attribute__((unused)), + uchar *prev_key __attribute__((unused)), + uchar *key, MI_KEY_PARAM *s_temp) { s_temp->key=key; return (int) (s_temp->totlength=keyinfo->keylength+nod_flag); @@ -1398,10 +1617,10 @@ _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag, int _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, - uchar *next_pos __attribute__((unused)), - uchar *org_key __attribute__((unused)), - uchar *prev_key __attribute__((unused)), - uchar *key, MI_KEY_PARAM *s_temp) + uchar *next_pos __attribute__((unused)), + uchar *org_key __attribute__((unused)), + uchar *prev_key __attribute__((unused)), + uchar *key, MI_KEY_PARAM *s_temp) { s_temp->key=key; return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag); @@ -1416,10 +1635,10 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, If the max length of first key segment <= 127 characters the prefix is 1 byte else it's 2 byte - prefix byte The high bit is set if this is a prefix for the prev key - length Packed length if the previous was a prefix byte - [length] Length character of data - next-key-seg Next key segments + prefix byte The high bit is set if this is a prefix for the prev key + length Packed length if the previous was a prefix byte + [length] Length character of data + next-key-seg Next key segments If the first segment can have NULL: The length is 0 for NULLS and 1+length for not null columns. @@ -1428,8 +1647,8 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, int _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, - uchar *org_key, uchar *prev_key, uchar *key, - MI_KEY_PARAM *s_temp) + uchar *org_key, uchar *prev_key, uchar *key, + MI_KEY_PARAM *s_temp) { reg1 MI_KEYSEG *keyseg; int length; @@ -1470,15 +1689,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, s_temp->key=key; s_temp->ref_length=s_temp->key_length=0; s_temp->totlength=key_length-1+diff_flag; - s_temp->next_key_pos=0; /* No next key */ + s_temp->next_key_pos=0; /* No next key */ return (s_temp->totlength); } s_temp->store_not_null=1; - key_length--; /* We don't store NULL */ + key_length--; /* We don't store NULL */ if (prev_key && !*prev_key++) - org_key=prev_key=0; /* Can't pack against prev */ + org_key=prev_key=0; /* Can't pack against prev */ else if (org_key) - org_key++; /* Skipp NULL */ + org_key++; /* Skipp NULL */ } else s_temp->store_not_null=0; @@ -1494,14 +1713,14 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if (prev_key) { get_key_length(org_key_length,prev_key); - s_temp->prev_key=prev_key; /* Pointer at data */ + s_temp->prev_key=prev_key; /* Pointer at data */ /* Don't use key-pack if length == 0 */ if (new_key_length && new_key_length == org_key_length) same_length=1; else if (new_key_length > org_key_length) end=key + org_key_length; - if (sort_order) /* SerG */ + if (sort_order) /* SerG */ { while (key < end && sort_order[*key] == sort_order[*prev_key]) { @@ -1512,7 +1731,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, { while (key < end && *key == *prev_key) { - key++; prev_key++; + key++; prev_key++; } } } @@ -1527,15 +1746,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, length=(int) key_length-(int) (key_end-start)-length_pack; length+= diff_flag; if (next_key) - { /* Can't combine with next */ - s_temp->n_length= *next_key; /* Needed by _mi_store_key */ + { /* Can't combine with next */ + s_temp->n_length= *next_key; /* Needed by _mi_store_key */ next_key=0; } } else { if (start != key) - { /* Starts as prev key */ + { /* Starts as prev key */ ref_length= (uint) (key-start); s_temp->ref_length= ref_length + pack_marker; length= (int) (key_length - ref_length); @@ -1546,16 +1765,16 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, } else { - s_temp->key_length+=s_temp->store_not_null; /* If null */ + s_temp->key_length+=s_temp->store_not_null; /* If null */ length= key_length - length_pack+ diff_flag; } } s_temp->totlength=(uint) length; s_temp->prev_length=0; DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d", - key_length,length,s_temp->key_length)); + key_length,length,s_temp->key_length)); - /* If something after that hasn't length=0, test if we can combine */ + /* If something after that hasn't length=0, test if we can combine */ if ((s_temp->next_key_pos=next_key)) { uint packed,n_length; @@ -1571,134 +1790,134 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if (!packed) n_length-= s_temp->store_not_null; - if (n_length || packed) /* Don't pack 0 length keys */ + if (n_length || packed) /* Don't pack 0 length keys */ { uint next_length_pack, new_ref_length=s_temp->ref_length; if (packed) { - /* If first key and next key is packed (only on delete) */ - if (!prev_key && org_key) - { - get_key_length(org_key_length,org_key); - key=start; - if (sort_order) /* SerG */ - { - while (key < end && sort_order[*key] == sort_order[*org_key]) - { - key++; org_key++; - } - } - else - { - while (key < end && *key == *org_key) - { - key++; org_key++; - } - } - if ((new_ref_length= (uint) (key - start))) - new_ref_length+=pack_marker; - } - - if (!n_length) - { - /* - We put a different key between two identical variable length keys - Extend next key to have same prefix as this key - */ - if (new_ref_length) /* prefix of previus key */ - { /* make next key longer */ - s_temp->part_of_prev_key= new_ref_length; - s_temp->prev_length= org_key_length - - (new_ref_length-pack_marker); - s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length; - n_length= get_pack_length(s_temp->prev_length); - s_temp->prev_key+= (new_ref_length - pack_marker); - length+= s_temp->prev_length + n_length; - } - else - { /* Can't use prev key */ - s_temp->part_of_prev_key=0; - s_temp->prev_length= org_key_length; - s_temp->n_ref_length=s_temp->n_length= org_key_length; - length+= org_key_length; - /* +get_pack_length(org_key_length); */ - } - return (int) length; - } - - ref_length=n_length; - get_key_pack_length(n_length,next_length_pack,next_key); - - /* Test if new keys has fewer characters that match the previous key */ - if (!new_ref_length) - { /* Can't use prev key */ - s_temp->part_of_prev_key= 0; - s_temp->prev_length= ref_length; - s_temp->n_ref_length= s_temp->n_length= n_length+ref_length; - /* s_temp->prev_key+= get_pack_length(org_key_length); */ - return (int) length+ref_length-next_length_pack; - } - if (ref_length+pack_marker > new_ref_length) - { - uint new_pack_length=new_ref_length-pack_marker; - /* We must copy characters from the original key to the next key */ - s_temp->part_of_prev_key= new_ref_length; - s_temp->prev_length= ref_length - new_pack_length; - s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length; - s_temp->prev_key+= new_pack_length; -/* +get_pack_length(org_key_length); */ - length= length-get_pack_length(ref_length)+ - get_pack_length(new_pack_length); - return (int) length + s_temp->prev_length; - } + /* If first key and next key is packed (only on delete) */ + if (!prev_key && org_key) + { + get_key_length(org_key_length,org_key); + key=start; + if (sort_order) /* SerG */ + { + while (key < end && sort_order[*key] == sort_order[*org_key]) + { + key++; org_key++; + } + } + else + { + while (key < end && *key == *org_key) + { + key++; org_key++; + } + } + if ((new_ref_length= (uint) (key - start))) + new_ref_length+=pack_marker; + } + + if (!n_length) + { + /* + We put a different key between two identical variable length keys + Extend next key to have same prefix as this key + */ + if (new_ref_length) /* prefix of previus key */ + { /* make next key longer */ + s_temp->part_of_prev_key= new_ref_length; + s_temp->prev_length= org_key_length - + (new_ref_length-pack_marker); + s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length; + n_length= get_pack_length(s_temp->prev_length); + s_temp->prev_key+= (new_ref_length - pack_marker); + length+= s_temp->prev_length + n_length; + } + else + { /* Can't use prev key */ + s_temp->part_of_prev_key=0; + s_temp->prev_length= org_key_length; + s_temp->n_ref_length=s_temp->n_length= org_key_length; + length+= org_key_length; + /* +get_pack_length(org_key_length); */ + } + return (int) length; + } + + ref_length=n_length; + get_key_pack_length(n_length,next_length_pack,next_key); + + /* Test if new keys has fewer characters that match the previous key */ + if (!new_ref_length) + { /* Can't use prev key */ + s_temp->part_of_prev_key= 0; + s_temp->prev_length= ref_length; + s_temp->n_ref_length= s_temp->n_length= n_length+ref_length; + /* s_temp->prev_key+= get_pack_length(org_key_length); */ + return (int) length+ref_length-next_length_pack; + } + if (ref_length+pack_marker > new_ref_length) + { + uint new_pack_length=new_ref_length-pack_marker; + /* We must copy characters from the original key to the next key */ + s_temp->part_of_prev_key= new_ref_length; + s_temp->prev_length= ref_length - new_pack_length; + s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length; + s_temp->prev_key+= new_pack_length; +/* +get_pack_length(org_key_length); */ + length= length-get_pack_length(ref_length)+ + get_pack_length(new_pack_length); + return (int) length + s_temp->prev_length; + } } else { - /* Next key wasn't a prefix of previous key */ - ref_length=0; - next_length_pack=0; + /* Next key wasn't a prefix of previous key */ + ref_length=0; + next_length_pack=0; } DBUG_PRINT("test",("length: %d next_key: %lx",length,next_key)); { - uint tmp_length; - key=(start+=ref_length); - if (key+n_length < key_end) /* Normalize length based */ - key_end=key+n_length; - if (sort_order) /* SerG */ - { + uint tmp_length; + key=(start+=ref_length); + if (key+n_length < key_end) /* Normalize length based */ + key_end=key+n_length; + if (sort_order) /* SerG */ + { while (key < key_end && sort_order[*key] == - sort_order[*next_key]) - { - key++; next_key++; - } - } - else - { - while (key < key_end && *key == *next_key) - { - key++; next_key++; - } - } - if (!(tmp_length=(uint) (key-start))) - { /* Key can't be re-packed */ - s_temp->next_key_pos=0; - return length; - } - ref_length+=tmp_length; - n_length-=tmp_length; - length-=tmp_length+next_length_pack; /* We gained these chars */ + sort_order[*next_key]) + { + key++; next_key++; + } + } + else + { + while (key < key_end && *key == *next_key) + { + key++; next_key++; + } + } + if (!(tmp_length=(uint) (key-start))) + { /* Key can't be re-packed */ + s_temp->next_key_pos=0; + return length; + } + ref_length+=tmp_length; + n_length-=tmp_length; + length-=tmp_length+next_length_pack; /* We gained these chars */ } if (n_length == 0) { - s_temp->n_ref_length=pack_marker; /* Same as prev key */ + s_temp->n_ref_length=pack_marker; /* Same as prev key */ } else { - s_temp->n_ref_length=ref_length | pack_marker; - length+= get_pack_length(n_length); - s_temp->n_length=n_length; + s_temp->n_ref_length=ref_length | pack_marker; + length+= get_pack_length(n_length); + s_temp->n_length=n_length; } } } @@ -1710,15 +1929,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, int _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, - uchar *org_key, uchar *prev_key, uchar *key, - MI_KEY_PARAM *s_temp) + uchar *org_key, uchar *prev_key, uchar *key, + MI_KEY_PARAM *s_temp) { uint length,key_length,ref_length; s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag; s_temp->key=key; s_temp->prev_key=org_key; - if (prev_key) /* If not first key in block */ + if (prev_key) /* If not first key in block */ { /* pack key against previous key */ /* @@ -1737,7 +1956,7 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, s_temp->ref_length=ref_length=0; length=key_length+1; } - if ((s_temp->next_key_pos=next_key)) /* If another key after */ + if ((s_temp->next_key_pos=next_key)) /* If another key after */ { /* pack key against next key */ uint next_length,next_length_pack; @@ -1748,21 +1967,21 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, { uchar *end; for (key= s_temp->key, end=key+next_length ; - *key == *org_key && key < end; - key++,org_key++) ; + *key == *org_key && key < end; + key++,org_key++) ; ref_length= (uint) (key - s_temp->key); } if (next_length > ref_length) { /* We put a key with different case between two keys with the same prefix - Extend next key to have same prefix as - this key */ + Extend next key to have same prefix as + this key */ s_temp->n_ref_length= ref_length; s_temp->prev_length= next_length-ref_length; s_temp->prev_key+= ref_length; return (int) (length+ s_temp->prev_length - next_length_pack + - get_pack_length(ref_length)); + get_pack_length(ref_length)); } /* Check how many characters are identical to next key */ key= s_temp->key+next_length; @@ -1770,12 +1989,12 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if ((ref_length= (uint) (key - s_temp->key)-1) == next_length) { s_temp->next_key_pos=0; - return length; /* can't pack next key */ + return length; /* can't pack next key */ } s_temp->prev_length=0; s_temp->n_ref_length=ref_length; return (int) (length-(ref_length - next_length) - next_length_pack + - get_pack_length(ref_length)); + get_pack_length(ref_length)); } return (int) length; } @@ -1788,8 +2007,8 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, /* store key without compression */ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength); } @@ -1803,8 +2022,8 @@ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)), void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { uint length; uchar *start; @@ -1825,9 +2044,9 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length); } bmove((byte*) key_pos,(byte*) s_temp->key, - (length=s_temp->totlength-(uint) (key_pos-start))); + (length=s_temp->totlength-(uint) (key_pos-start))); - if (!s_temp->next_key_pos) /* No following key */ + if (!s_temp->next_key_pos) /* No following key */ return; key_pos+=length; @@ -1837,14 +2056,14 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), if (s_temp->part_of_prev_key) { store_pack_length(s_temp->pack_marker == 128,key_pos, - s_temp->part_of_prev_key); + s_temp->part_of_prev_key); store_key_length_inc(key_pos,s_temp->n_length); } else { s_temp->n_length+= s_temp->store_not_null; store_pack_length(s_temp->pack_marker == 128,key_pos, - s_temp->n_length); + s_temp->n_length); } memcpy(key_pos, s_temp->prev_key, s_temp->prev_length); } @@ -1852,7 +2071,7 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), { store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length); if (s_temp->n_ref_length == s_temp->pack_marker) - return; /* Identical key */ + return; /* Identical key */ store_key_length(key_pos,s_temp->n_length); } else @@ -1866,18 +2085,18 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), /* variable length key with prefix compression */ void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { store_key_length_inc(key_pos,s_temp->ref_length); memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length, - (size_t) s_temp->totlength-s_temp->ref_length); + (size_t) s_temp->totlength-s_temp->ref_length); if (s_temp->next_key_pos) { key_pos+=(uint) (s_temp->totlength-s_temp->ref_length); store_key_length_inc(key_pos,s_temp->n_ref_length); - if (s_temp->prev_length) /* If we must extend key */ + if (s_temp->prev_length) /* If we must extend key */ { memcpy(key_pos,s_temp->prev_key,s_temp->prev_length); } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f790f90ca78..389aac3142a 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -32,7 +32,7 @@ my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; uint myisam_block_size=MI_KEY_BLOCK_LENGTH; /* Best by test */ -my_bool myisam_flush=0,myisam_delay_key_write=0; +my_bool myisam_flush=0, myisam_delay_key_write=0, myisam_single_user=0; #if defined(THREAD) && !defined(DONT_USE_RW_LOCKS) my_bool myisam_concurrent_insert=1; #else @@ -40,7 +40,7 @@ my_bool myisam_concurrent_insert=0; #endif my_off_t myisam_max_extra_temp_length= MI_MAX_TEMP_LENGTH; my_off_t myisam_max_temp_length= MAX_FILE_SIZE; - +uint myisam_bulk_insert_tree_size=8192*1024; /* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */ /* Position is , == , >= , <= , > , < */ diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c index 05ff40d8921..e0fce6d3e1c 100644 --- a/myisam/mi_statrec.c +++ b/myisam/mi_statrec.c @@ -27,17 +27,16 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) { my_off_t filepos=info->s->state.dellink; info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0))); - - if (my_read(info->dfile,(char*) &temp[0],info->s->base.rec_reflength, - MYF(MY_NABP))) + if (my_pread(info->dfile,(char*) &temp[0],info->s->base.rec_reflength, + info->s->state.dellink+1, + MYF(MY_NABP))) goto err; info->s->state.dellink= _mi_rec_pos(info->s,temp); info->state->del--; info->state->empty-=info->s->base.pack_reclength; - VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); - if (my_write(info->dfile, (char*) record, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pwrite(info->dfile, (char*) record, info->s->base.reclength, + filepos, + MYF(MY_NABP))) goto err; } else @@ -64,16 +63,18 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) else { info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->state->data_file_length, - MY_SEEK_SET,MYF(0))); - if (my_write(info->dfile,(char*) record,info->s->base.reclength, - info->s->write_flag)) + if (my_pwrite(info->dfile,(char*) record,info->s->base.reclength, + info->state->data_file_length, + info->s->write_flag)) goto err; if (info->s->base.pack_reclength != info->s->base.reclength) { uint length=info->s->base.pack_reclength - info->s->base.reclength; bzero((char*) temp,length); - if (my_write(info->dfile, (byte*) temp,length, info->s->write_flag)) + if (my_pwrite(info->dfile, (byte*) temp,length, + info->state->data_file_length+ + info->s->base.reclength, + info->s->write_flag)) goto err; } } @@ -88,9 +89,10 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) int _mi_update_static_record(MI_INFO *info, my_off_t pos, const byte *record) { info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0))); - return (my_write(info->dfile,(char*) record,info->s->base.reclength, - MYF(MY_NABP)) != 0); + return (my_pwrite(info->dfile, + (char*) record,info->s->base.reclength, + pos, + MYF(MY_NABP)) != 0); } @@ -104,9 +106,8 @@ int _mi_delete_static_record(MI_INFO *info) _mi_dpointer(info,temp+1,info->s->state.dellink); info->s->state.dellink = info->lastpos; info->rec_cache.seek_not_done=1; - VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0))); - return (my_write(info->dfile,(byte*) temp, 1+info->s->rec_reflength, - MYF(MY_NABP)) != 0); + return (my_pwrite(info->dfile,(byte*) temp, 1+info->s->rec_reflength, + info->lastpos, MYF(MY_NABP)) != 0); } @@ -129,9 +130,9 @@ int _mi_cmp_static_record(register MI_INFO *info, register const byte *old) if ((info->opt_flag & READ_CHECK_USED)) { /* If check isn't disabled */ info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0))); - if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength, + info->lastpos, + MYF(MY_NABP))) DBUG_RETURN(-1); if (memcmp((byte*) info->rec_buff, (byte*) old, (uint) info->s->base.reclength)) @@ -152,9 +153,8 @@ int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def, DBUG_ENTER("_mi_cmp_static_unique"); info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0))); - if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength, + pos, MYF(MY_NABP))) DBUG_RETURN(-1); DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff, def->null_are_equal)); diff --git a/myisam/mi_update.c b/myisam/mi_update.c index 185624f3878..ac843dbb6bd 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -98,9 +98,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) if ((int) i == info->lastinx) key_changed|=HA_STATE_WRITTEN; changed|=((ulonglong) 1 << i); - if (_mi_ft_del(info,i,(char*) old_key,oldrec,pos)) - goto err; - if (_mi_ft_add(info,i,(char*) new_key,newrec,pos)) + if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos)) goto err; } } diff --git a/myisam/mi_write.c b/myisam/mi_write.c index f31e43e52ab..81064dd1d6a 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -35,7 +35,10 @@ static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint *return_key_length, uchar **after_key); - +int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, + uint key_length); +int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, + uint key_length); /* Write new record to database */ @@ -96,27 +99,27 @@ int mi_write(MI_INFO *info, byte *record) { if (((ulonglong) 1 << i) & share->state.key_map) { - if (share->concurrent_insert) + if (share->concurrent_insert && ! info->bulk_insert) { rw_wrlock(&share->key_root_lock[i]); share->keyinfo[i].version++; } - if (share->keyinfo[i].flag & HA_FULLTEXT ) /* SerG */ - { /* SerG */ - if (_mi_ft_add(info,i,(char*) buff,record,filepos)) /* SerG */ - { /* SerG */ + if (share->keyinfo[i].flag & HA_FULLTEXT ) + { + if (_mi_ft_add(info,i,(char*) buff,record,filepos)) + { if (share->concurrent_insert) rw_unlock(&share->key_root_lock[i]); - DBUG_PRINT("error",("Got error: %d on write",my_errno)); /* SerG */ - goto err; /* SerG */ - } /* SerG */ - } /* SerG */ - else /* SerG */ + DBUG_PRINT("error",("Got error: %d on write",my_errno)); + goto err; + } + } + else { uint key_length=_mi_make_key(info,i,buff,record,filepos); if (_mi_ck_write(info,i,buff,key_length)) { - if (share->concurrent_insert) + if (share->concurrent_insert && ! info->bulk_insert) rw_unlock(&share->key_root_lock[i]); DBUG_PRINT("error",("Got error: %d on write",my_errno)); goto err; @@ -156,7 +159,6 @@ err: { if (share->concurrent_insert) rw_wrlock(&share->key_root_lock[i]); - /* The following code block is for text searching by SerG */ if (share->keyinfo[i].flag & HA_FULLTEXT) { if (_mi_ft_del(info,i,(char*) buff,record,filepos)) @@ -196,19 +198,37 @@ err2: /* Write one key to btree */ -int _mi_ck_write(register MI_INFO *info, uint keynr, uchar *key, - uint key_length) +int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint key_length) { - int error; DBUG_ENTER("_mi_ck_write"); + if (info->bulk_insert && is_tree_inited(& info->bulk_insert[keynr])) + { + DBUG_RETURN(_mi_ck_write_tree(info, keynr, key, key_length)); + } + else + { + DBUG_RETURN(_mi_ck_write_btree(info, keynr, key, key_length)); + } +} /* _mi_ck_write */ + +/********************************************************************** + * Normal insert code * + **********************************************************************/ + +int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, + uint key_length) +{ + int error; + DBUG_ENTER("_mi_ck_write_btree"); + if (info->s->state.key_root[keynr] == HA_OFFSET_ERROR || (error=w_search(info,info->s->keyinfo+keynr,key, key_length, info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0, (my_off_t) 0, 1)) > 0) error=_mi_enlarge_root(info,keynr,key); DBUG_RETURN(error); -} /* _mi_ck_write */ +} /* _mi_ck_write_btree */ /* Make a new root with key as only pointer */ @@ -682,3 +702,113 @@ static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo, err: DBUG_RETURN(-1); } /* _mi_balance_page */ + +/********************************************************************** + * Bulk insert code * + **********************************************************************/ + +typedef struct { + MI_INFO *info; + uint keynr; +} bulk_insert_param; + +int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, + uint key_length) +{ + int error; + DBUG_ENTER("_mi_ck_write_tree"); + + error= tree_insert(& info->bulk_insert[keynr], key, + key_length + info->s->rec_reflength) ? 0 : HA_ERR_OUT_OF_MEM ; + + DBUG_RETURN(error); +} /* _mi_ck_write_tree */ + +/* typeof(_mi_keys_compare)=qsort_cmp2 */ +static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2) +{ + uint not_used; + return _mi_key_cmp(param->info->s->keyinfo[param->keynr].seg, + key1, key2, USE_WHOLE_KEY, SEARCH_SAME, ¬_used); +} + +static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param) +{ + /* probably I can use info->lastkey here, but I'm not sure, + and to be safe I'd better use local lastkey. + Monty, feel free to comment on this */ + uchar lastkey[MI_MAX_KEY_BUFF]; + uint keylen; + MI_KEYDEF *keyinfo; + + switch (mode) { + case free_init: + if (param->info->s->concurrent_insert) + { + rw_wrlock(¶m->info->s->key_root_lock[param->keynr]); + param->info->s->keyinfo[param->keynr].version++; + } + return 0; + case free_free: + keyinfo=param->info->s->keyinfo+param->keynr; + keylen=_mi_keylength(keyinfo, key); + memcpy(lastkey, key, keylen); + return _mi_ck_write_btree(param->info,param->keynr,lastkey, + keylen - param->info->s->rec_reflength); + case free_end: + if (param->info->s->concurrent_insert) + rw_unlock(¶m->info->s->key_root_lock[param->keynr]); + return 0; + } + return -1; +} + +int _mi_init_bulk_insert(MI_INFO *info) +{ + MYISAM_SHARE *share=info->s; + MI_KEYDEF *key=share->keyinfo; + bulk_insert_param *params; + uint i, num_keys; + ulonglong key_map=0; + + if (info->bulk_insert) + return 0; + + for (i=num_keys=0 ; i < share->base.keys ; i++) + { + if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1 + && test(share->state.key_map & ((ulonglong) 1 << i))) + { + num_keys++; + key_map |=((ulonglong) 1 << i); + } + } + + if (!num_keys) + return 0; + + info->bulk_insert=(TREE *) + my_malloc((sizeof(TREE)*share->base.keys+ + sizeof(bulk_insert_param)*num_keys),MYF(0)); + + if (!info->bulk_insert) + return HA_ERR_OUT_OF_MEM; + + params=(bulk_insert_param *)(info->bulk_insert+share->base.keys); + for (i=0 ; i < share->base.keys ; i++,key++) + { + if (test(key_map & ((ulonglong) 1 << i))) + { + params->info=info; + params->keynr=i; + init_tree(& info->bulk_insert[i], 0, + myisam_bulk_insert_tree_size / num_keys, 0, + (qsort_cmp2)keys_compare, 0, + (tree_element_free) keys_free, (void *)params++); + } + else + info->bulk_insert[i].root=0; + } + + return 0; +} diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index aa0713437f4..6f782b2f80f 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -151,6 +151,12 @@ static CHANGEABLE_VAR changeable_vars[] = { { "sort_key_blocks",(long*) &check_param.sort_key_blocks,BUFFERS_WHEN_SORTING,4L,100L,0L, 1L }, { "decode_bits",(long*) &decode_bits,9L,4L,17L,0L,1L }, + { "ft_min_word_len", (long*) &ft_min_word_len, + 4, 1, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len", (long*) &ft_max_word_len, + HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len_for_sort",(long*) &ft_max_word_len_for_sort, + 20, 4, HA_FT_MAXLEN, 0, 1 }, { NullS,(long*) 0,0L,0L,0L,0L,0L,} }; enum options {OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS}; @@ -176,7 +182,6 @@ static struct option long_options[] = {"information", no_argument, 0, 'i'}, {"keys-used", required_argument, 0, 'k'}, {"medium-check", no_argument, 0, 'm'}, - {"no-symlinks", no_argument, 0, 'l'}, {"quick", no_argument, 0, 'q'}, {"read-only", no_argument, 0, 'T'}, {"recover", no_argument, 0, 'r'}, @@ -252,8 +257,6 @@ static void usage(void) -k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\ bit mask of which keys to use. This can be used to\n\ get faster inserts!\n\ - -l, --no-symlinks Do not follow symbolic links. Normally\n\ - myisamchk repairs the table a symlink points at.\n\ -r, --recover Can fix almost anything except unique keys that aren't\n\ unique.\n\ -n, --sort-recover Force recovering with sorting even if the temporary\n\ @@ -367,9 +370,6 @@ static void get_options(register int *argc,register char ***argv) case 'k': check_param.keys_in_use= (ulonglong) strtoll(optarg,NULL,10); break; - case 'l': - check_param.opt_follow_links=0; - break; case 'm': check_param.testflag|= T_MEDIUM; /* Medium check */ break; @@ -492,7 +492,6 @@ static int myisamchk(MI_CHECK *param, my_string filename) uint raid_chunks; MI_INFO *info; File datafile; - char fixed_name[FN_REFLEN]; char llbuff[22],llbuff2[22]; my_bool state_updated=0; MYISAM_SHARE *share; @@ -670,9 +669,6 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (tmp != share->state.key_map) info->update|=HA_STATE_CHANGED; } - VOID(fn_format(fixed_name,filename,"",MI_NAME_IEXT, - 4+ (param->opt_follow_links ? 16 : 0))); - if (rep_quick && chk_del(&check_param, info, param->testflag & ~T_VERBOSE)) { @@ -697,11 +693,11 @@ static int myisamchk(MI_CHECK *param, my_string filename) info->s->state.key_map, check_param.force_sort)) { - error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick); + error=mi_repair_by_sort(&check_param,info,filename,rep_quick); state_updated=1; } else if (param->testflag & (T_REP | T_REP_BY_SORT)) - error=mi_repair(&check_param, info,fixed_name,rep_quick); + error=mi_repair(&check_param, info,filename,rep_quick); } if (!error && param->testflag & T_SORT_RECORDS) { @@ -713,10 +709,10 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (param->out_flag & O_NEW_DATA) { /* Change temp file to org file */ VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */ - error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT, + error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT, raid_chunks, MYF(0)); - if (mi_open_datafile(info,info->s)) + if (mi_open_datafile(info,info->s, -1)) error=1; param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */ param->read_cache.file=info->dfile; @@ -734,7 +730,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (share->keyinfo[key].flag & HA_BINARY_PACK_KEY) update_index=0; - error=mi_sort_records(param,info,fixed_name,param->opt_sort_key, + error=mi_sort_records(param,info,filename,param->opt_sort_key, (my_bool) !(param->testflag & T_REP), update_index); datafile=info->dfile; /* This is now locked */ @@ -742,12 +738,12 @@ static int myisamchk(MI_CHECK *param, my_string filename) { if (check_param.verbose) puts("Table had a compressed index; We must now recreate the index"); - error=mi_repair_by_sort(&check_param,info,fixed_name,1); + error=mi_repair_by_sort(&check_param,info,filename,1); } } } if (!error && param->testflag & T_SORT_INDEX) - error=mi_sort_index(param,info,fixed_name); + error=mi_sort_index(param,info,filename); if (!error) share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED | STATE_CRASHED_ON_REPAIR); @@ -844,12 +840,12 @@ end2: if (error == 0) { if (param->out_flag & O_NEW_DATA) - error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT, + error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT, raid_chunks, ((param->testflag & T_BACKUP_DATA) ? MYF(MY_REDEL_MAKE_BACKUP) : MYF(0))); if (param->out_flag & O_NEW_INDEX) - error|=change_to_newfile(fixed_name,MI_NAME_IEXT,INDEX_TMP_EXT,0, + error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0, MYF(0)); } VOID(fflush(stdout)); VOID(fflush(stderr)); @@ -1207,7 +1203,9 @@ static int mi_sort_records(MI_CHECK *param, mi_check_print_error(param,"Not enough memory for record"); goto err; } - new_file=my_raid_create(fn_format(param->temp_filename,name,"", + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename,"", DATA_TMP_EXT,2+4), 0,param->tmpfile_createflag, share->base.raid_type, diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 33fd1b6946f..9da669e8438 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + 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 */ @@ -18,6 +18,7 @@ #include "myisam.h" /* Structs & some defines */ #include "myisampack.h" /* packing of keys */ +#include <my_tree.h> #ifdef THREAD #include <my_pthread.h> #include <thr_lock.h> @@ -37,7 +38,7 @@ typedef struct st_mi_status_info my_off_t key_empty; /* lost space in indexfile */ my_off_t key_file_length; my_off_t data_file_length; -} MI_STATUS_INFO; +} MI_STATUS_INFO; typedef struct st_mi_state_info { @@ -159,15 +160,17 @@ typedef struct st_mi_isam_share { /* Shared between opens */ MI_COLUMNDEF *rec; /* Pointer to field information */ MI_PACK pack; /* Data about packed records */ MI_BLOB *blobs; /* Pointer to blobs */ - char *filename; /* Name of indexfile */ + char *unique_file_name; /* realpath() of index file */ + char *data_file_name, /* Resolved path names from symlinks */ + *index_file_name; byte *file_map; /* mem-map of file if possible */ ulong this_process; /* processid */ ulong last_process; /* For table-change-check */ ulong last_version; /* Version on start */ ulong options; /* Options used */ uint rec_reflength; /* rec_reflength in use now */ - int kfile; /* Shared keyfile */ - int data_file; /* Shared data file */ + File kfile; /* Shared keyfile */ + File data_file; /* Shared data file */ int mode; /* mode of file on open */ uint reopen; /* How many times reopened */ uint w_locks,r_locks; /* Number of read/write locks */ @@ -259,6 +262,7 @@ struct st_myisam_info { my_bool page_changed; /* If info->buff can't be used for rnext */ my_bool buff_used; /* If info->buff has to be reread for rnext */ my_bool use_packed_key; /* For MYISAMMRG */ + TREE *bulk_insert; /* accumulate indexfile changes between mi_write's */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ int (*read_record)(struct st_myisam_info*, my_off_t, byte*); LIST open_list; @@ -285,7 +289,7 @@ struct st_myisam_info { #define STATE_CHANGED 1 #define STATE_CRASHED 2 -#define STATE_CRASHED_ON_REPAIR 4 +#define STATE_CRASHED_ON_REPAIR 4 #define STATE_NOT_ANALYZED 8 #define STATE_NOT_OPTIMIZED_KEYS 16 #define STATE_NOT_SORTED_PAGES 32 @@ -473,6 +477,9 @@ extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo, extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, uchar *key,uint key_len,uint comp_flag, uchar **ret_pos,uchar *buff, my_bool *was_last_key); +extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, + uchar *key,uint key_len,uint comp_flag, + uchar **ret_pos,uchar *buff, my_bool *was_last_key); extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint , my_bool); extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key); @@ -528,6 +535,8 @@ extern int _mi_read_rnd_pack_record(MI_INFO*, byte *,my_off_t, my_bool); extern int _mi_pack_rec_unpack(MI_INFO *info,byte *to,byte *from, ulong reclength); extern ulonglong mi_safe_mul(ulonglong a,ulonglong b); +extern int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, + const byte *oldrec, const byte *newrec, my_off_t pos); struct st_sort_info; @@ -633,13 +642,16 @@ my_bool mi_check_status(void* param); void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows); my_bool check_table_is_closed(const char *name, const char *where); -int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share); +int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup); int mi_open_keyfile(MYISAM_SHARE *share); -/* Functions needed by mi_check */ +int _mi_init_bulk_insert(MI_INFO *info); + + /* Functions needed by mi_check */ void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...)); +int flush_pending_blocks(MI_CHECK *param); #ifdef __cplusplus } diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index ddfafb91430..fb199c22765 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -56,7 +56,7 @@ extern int main(int argc,char * *argv); static void get_options(int *argc,char ***argv); static int examine_log(my_string file_name,char **table_names); static int read_string(IO_CACHE *file,gptr *to,uint length); -static int file_info_compare(void *a,void *b); +static int file_info_compare(void *cmp_arg, void *a,void *b); static int test_if_open(struct file_info *key,element_count count, struct test_if_open_param *param); static void fix_blob_pointers(MI_INFO *isam,byte *record); @@ -331,8 +331,8 @@ static int examine_log(my_string file_name, char **table_names) init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0)); bzero((gptr) com_count,sizeof(com_count)); - init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1, - (void(*)(void*)) file_info_free); + init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1, + (tree_element_free) file_info_free, NULL); VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD)))); files_open=0; access_time=0; @@ -695,7 +695,8 @@ static int read_string(IO_CACHE *file, register gptr *to, register uint length) } /* read_string */ -static int file_info_compare(void *a, void *b) +static int file_info_compare(void* cmp_arg __attribute__((unused)), + void *a, void *b) { long lint; diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 54a8db457e8..9408198400f 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -124,7 +124,8 @@ static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees, HUFF_COUNTS *huff_counts, uint fields); -static int compare_tree(const uchar *s,const uchar *t); +static int compare_tree(void* cmp_arg __attribute__((unused)), + const uchar *s,const uchar *t); static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts); static void check_counts(HUFF_COUNTS *huff_counts,uint trees, my_off_t records); @@ -673,7 +674,7 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIPP_ZERO)) count[i].max_zero_fill= count[i].field_length; - init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL); + init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL); if (records && type != FIELD_BLOB && type != FIELD_VARCHAR) count[i].tree_pos=count[i].tree_buff = my_malloc(count[i].field_length > 1 ? tree_buff_length : 2, @@ -893,7 +894,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) DBUG_RETURN(error != HA_ERR_END_OF_FILE); } -static int compare_huff_elements(void *not_used, byte *a, byte *b) +static int compare_huff_elements(void* cmp_arg __attribute__((unused)), + byte *a, byte *b) { return *((my_off_t*) a) < *((my_off_t*) b) ? -1 : (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1); @@ -1289,7 +1291,8 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) return 0; } -static int compare_tree(register const uchar *s, register const uchar *t) +static int compare_tree(void* cmp_arg __attribute__((unused)), + register const uchar *s, register const uchar *t) { uint length; for (length=global_count->field_length; length-- ;) diff --git a/myisam/sort.c b/myisam/sort.c index 161a5f92bf5..e78ccc8c136 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + 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 */ @@ -19,7 +19,7 @@ them in sorted order through SORT_INFO functions. */ -#include "myisamdef.h" +#include "fulltext.h" #if defined(MSDOS) || defined(__WIN__) #include <fcntl.h> #else @@ -52,10 +52,12 @@ extern void print_error _VARARGS((const char *fmt,...)); static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys, uchar **sort_keys, - BUFFPEK *buffpek,int *maxbuffer, - IO_CACHE *tempfile); + DYNAMIC_ARRAY *buffpek,int *maxbuffer, + IO_CACHE *tempfile, + IO_CACHE *tempfile_for_exceptions); static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys, uint count, BUFFPEK *buffpek,IO_CACHE *tempfile); +static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile); static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys, uint count); static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys, @@ -70,7 +72,6 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys, BUFFPEK *Fb, BUFFPEK *Tb); static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int, IO_CACHE *); -static char **make_char_array(uint fields,uint length,myf my_flag); /* Creates a index of sorted keys */ /* Returns 0 if everything went ok */ @@ -80,15 +81,17 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, { int error,maxbuffer,skr; uint memavl,old_memavl,keys,sort_length; - BUFFPEK *buffpek; + DYNAMIC_ARRAY buffpek; ha_rows records; uchar **sort_keys; - IO_CACHE tempfile; + IO_CACHE tempfile, tempfile_for_exceptions; DBUG_ENTER("_create_index_by_sort"); DBUG_PRINT("enter",("sort_length: %d", info->key_length)); my_b_clear(&tempfile); - buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1; + my_b_clear(&tempfile_for_exceptions); + bzero((char*) &buffpek,sizeof(buffpek)); + sort_keys= (uchar **) NULL; error= 1; maxbuffer=1; memavl=max(sortbuff_size,MIN_SORT_MEMORY); @@ -116,14 +119,14 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, } while ((maxbuffer= (int) (records/(keys-1)+1)) != skr); - if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0)))) + if ((sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+ + HA_FT_MAXLEN, MYF(0)))) { - if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)* - (uint) maxbuffer), - MYF(0)))) - break; - else + if (init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer, + maxbuffer/2)) my_free((gptr) sort_keys,MYF(0)); + else + break; } old_memavl=memavl; if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY) @@ -139,7 +142,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, if (!no_messages) printf(" - Searching for keys, allocating buffer for %d keys\n",keys); - if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile)) + if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer, + &tempfile,&tempfile_for_exceptions)) == HA_POS_ERROR) goto err; /* purecov: tested */ if (maxbuffer == 0) @@ -156,7 +160,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, { if (!no_messages) printf(" - Merging %lu keys\n",records); /* purecov: tested */ - if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile)) + if (merge_many_buff(info,keys,sort_keys, + dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile)) goto err; /* purecov: inspected */ } if (flush_io_cache(&tempfile) || @@ -164,17 +169,39 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, goto err; /* purecov: inspected */ if (!no_messages) puts(" - Last merge and dumping keys"); /* purecov: tested */ - if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile)) + if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *), + maxbuffer,&tempfile)) goto err; /* purecov: inspected */ } + + if (flush_pending_blocks(info->sort_info->param)) + goto err; + + if (my_b_inited(&tempfile_for_exceptions)) + { + MI_INFO *index=info->sort_info->info; + uint keyno=info->sort_info->key; + uint key_length, ref_length=index->s->rec_reflength; + + if (flush_io_cache(&tempfile_for_exceptions) || + reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0)) + goto err; + + while (!my_b_read(&tempfile_for_exceptions,(byte*)&key_length, sizeof(key_length)) + && !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,(uint)key_length)) + { + if (_mi_ck_write(index,keyno,(byte*)sort_keys,key_length-ref_length)) goto err; + } + } + error =0; err: if (sort_keys) my_free((gptr) sort_keys,MYF(0)); - if (buffpek) - my_free((gptr) buffpek,MYF(0)); + delete_dynamic(&buffpek); close_cached_file(&tempfile); + close_cached_file(&tempfile_for_exceptions); DBUG_RETURN(error ? -1 : 0); } /* _create_index_by_sort */ @@ -183,36 +210,50 @@ err: /* Search after all keys and place them in a temp. file */ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, - uchar **sort_keys, BUFFPEK *buffpek, - int *maxbuffer, IO_CACHE *tempfile) + uchar **sort_keys, DYNAMIC_ARRAY *buffpek, + int *maxbuffer, IO_CACHE *tempfile, + IO_CACHE *tempfile_for_exceptions) { int error; - uint idx,indexpos; + uint idx; DBUG_ENTER("find_all_keys"); - idx=indexpos=error=0; + idx=error=0; + sort_keys[0]=(char*)(sort_keys+keys); - while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx]))) + while(!(error=(*info->key_read)(info->sort_info,sort_keys[idx]))) { - if ((uint) ++idx == keys) + if (info->sort_info->real_key_length > info->key_length) { - if (indexpos >= (uint) *maxbuffer || - write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile)) - DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + if (write_key(info,sort_keys[idx],tempfile_for_exceptions)) + DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + continue; + } + + if (++idx == keys) + { + if (write_keys(info,sort_keys,idx-1,(BUFFPEK *)alloc_dynamic(buffpek),tempfile)) + DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + + sort_keys[0]=(char*)(sort_keys+keys); memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length); - idx=1; indexpos++; + idx=1; } + sort_keys[idx]=sort_keys[idx-1]+info->key_length; } if (error > 0) DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */ - if (indexpos) - if (indexpos >= (uint) *maxbuffer || - write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile)) + if (buffpek->elements) + { + if (write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),tempfile)) DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ - *maxbuffer=(int) indexpos; - DBUG_RETURN(indexpos*(keys-1)+idx); -} /* find_all_keys */ + *maxbuffer=buffpek->elements-1; + } + else + *maxbuffer=0; + DBUG_RETURN((*maxbuffer)*(keys-1)+idx); +} /* find_all_keys */ /* Write all keys in memory to file for later merge */ @@ -225,11 +266,12 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, DBUG_ENTER("write_keys"); qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info->sort_info); + info->sort_info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, info->myf_rw)) DBUG_RETURN(1); /* purecov: inspected */ + buffpek->file_pos=my_b_tell(tempfile); buffpek->count=count; @@ -240,6 +282,22 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, } /* write_keys */ +static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile) +{ + uint key_length=info->sort_info->real_key_length; + DBUG_ENTER("write_key"); + + if (!my_b_inited(tempfile) && + open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, + info->myf_rw)) + DBUG_RETURN(1); + + if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) || + my_b_write(tempfile,(byte*)key,(uint) key_length)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} /* write_key */ + /* Write index */ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, @@ -329,7 +387,7 @@ static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, /* If to_file == 0 then use info->key_write */ static int NEAR_F -merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file, +merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file, IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb) { @@ -475,21 +533,3 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys, DBUG_RETURN(0); } /* merge_index */ - - /* Make a pointer of arrays to keys */ - -static char **make_char_array(register uint fields, uint length, myf my_flag) -{ - register char **pos; - char **old_pos,*char_pos; - DBUG_ENTER("make_char_array"); - - if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag))) - { - pos=old_pos; char_pos=((char*) (pos+fields)) -length; - while (fields--) - *(pos++) = (char_pos+= length); - } - - DBUG_RETURN(old_pos); -} /* make_char_array */ diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index df94fb680cb..9fa89b315ff 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -36,7 +36,7 @@ int mode, int handle_locking) { int save_errno,i,errpos; - uint files,dir_length,length; + uint files,dir_length,length,options; ulonglong file_offset; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; MYRG_INFO info,*m_info; @@ -92,16 +92,22 @@ int handle_locking) m_info->tables=files; errpos=2; + options= (uint) ~0; for (i=files ; i-- > 0 ; ) { m_info->open_tables[i].table=isam; m_info->options|=isam->s->options; + options&=isam->s->options; m_info->records+=isam->state->records; m_info->del+=isam->state->del; m_info->data_file_length+=isam->state->data_file_length; if (i) isam=(MI_INFO*) (isam->open_list.next->data); } + /* Don't force readonly if not all tables are readonly */ + if (! (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA))) + m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA); + /* Fix fileinfo for easyer debugging (actually set by rrnd) */ file_offset=0; for (i=0 ; (uint) i < files ; i++) diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index d98c10a29a9..91333dfad9b 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -59,6 +59,8 @@ SUFFIXES = .sh -e 's!@''libexecdir''@!$(libexecdir)!g' \ -e 's!@''PERL''@!@PERL@!' \ -e 's!@''VERSION''@!@VERSION@!' \ + -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \ + -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \ -e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \ $< > $@-t @CHMOD@ +x $@-t diff --git a/mysql-test/fix-result b/mysql-test/fix-result new file mode 100755 index 00000000000..7060db36e03 --- /dev/null +++ b/mysql-test/fix-result @@ -0,0 +1,22 @@ +#! /bin/sh + +# Sasha's hack to fix results generated with mysql-test-run --record +# to be version and test port independent. In some cases, further minor +# manual edititing may be required, but most of the time it should not +# happen + +#It is assumed we are running the script in mysql-test directory + +VERSION=4.0.0-debug-log +TEST_CASE=$1 + +if [ -z "$TEST_CASE" ] ; +then + echo "usage: $0 test_case_name" + exit 1 +fi + +../extra/replace $VERSION '$VERSION' 9306 '$MASTER_MYPORT' 9307 \ +'$SLAVE_MYPORT' \\ \\\\ -- r/$TEST_CASE.result + + diff --git a/mysql-test/include/have_openssl.inc b/mysql-test/include/have_openssl.inc new file mode 100644 index 00000000000..b9aa2dadb9e --- /dev/null +++ b/mysql-test/include/have_openssl.inc @@ -0,0 +1,2 @@ +-- require r/have_openssl.require +show variables like "have_openssl"; diff --git a/mysql-test/include/have_openssl_1.inc b/mysql-test/include/have_openssl_1.inc new file mode 100644 index 00000000000..5aa93b688f3 --- /dev/null +++ b/mysql-test/include/have_openssl_1.inc @@ -0,0 +1,2 @@ +-- require r/have_openssl_1.require +show variables like "have_openssl"; diff --git a/mysql-test/include/have_openssl_2.inc b/mysql-test/include/have_openssl_2.inc new file mode 100644 index 00000000000..b15af43715b --- /dev/null +++ b/mysql-test/include/have_openssl_2.inc @@ -0,0 +1,2 @@ +-- require r/have_openssl_2.require +SHOW STATUS LIKE "SSL_get_cipher"; diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh index 6fe736644d3..0535b66e289 100644 --- a/mysql-test/install_test_db.sh +++ b/mysql-test/install_test_db.sh @@ -30,7 +30,7 @@ else fi mdata=$data/mysql - +EXTRA_ARG="" if test ! -x $execdir/mysqld then @@ -57,9 +57,7 @@ if [ x$BINARY_DIST = x1 ] ; then basedir=.. else basedir=. -rm -rf share -mkdir share -ln -f -s ../../sql/share share/mysql +EXTRA_ARG="--language=../sql/share/english/" fi # Initialize variables @@ -136,16 +134,20 @@ then c_u="$c_u References_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Index_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Alter_priv enum('N','Y') DEFAULT 'N' NOT NULL," + c_u="$c_u ssl_type enum('none', 'cipher', 'x509','issuer','subject') NOT NULL," + c_u="$c_u ssl_cipher char(60) NULL," + c_u="$c_u x509_issuer blob NULL," + c_u="$c_u x509_subject blob NULL," c_u="$c_u PRIMARY KEY Host (Host,User)" c_u="$c_u )" c_u="$c_u comment='Users and global privileges';" - i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); - INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); - REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); + i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL); + INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL); + REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','none',NULL,NULL,NULL); - INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N'); - INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N');" + INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','none',NULL,NULL,NULL); + INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','none',NULL,NULL,NULL);" fi if test ! -f $mdata/func.frm @@ -192,8 +194,11 @@ then c_c="$c_c comment='Column privileges';" fi -if $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \ - --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb --skip-gemini << END_OF_DATA +mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \ + --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb --skip-gemini $EXTRA_ARG" +echo "running $mysqld_boot" + +if $mysqld_boot << END_OF_DATA use mysql; $c_d $i_d @@ -213,5 +218,6 @@ END_OF_DATA then exit 0 else + echo "Error executing mysqld --boostrap" exit 1 fi diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 4d987e591e0..e876eb2264d 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -99,8 +99,9 @@ export MYSQL_TEST_DIR STD_DATA=$MYSQL_TEST_DIR/std_data hostname=`hostname` # Installed in the mysql privilege table -TESTDIR="$MYSQL_TEST_DIR/t/" +TESTDIR="$MYSQL_TEST_DIR/t" TESTSUFFIX=test +TOT_SKIP=0 TOT_PASS=0 TOT_FAIL=0 TOT_TEST=0 @@ -108,6 +109,7 @@ USERT=0 SYST=0 REALT=0 MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp +SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging RES_SPACE=" " MYSQLD_SRC_DIRS="strings mysys include extra regex isam merge myisam \ myisammrg heap sql" @@ -124,7 +126,9 @@ USE_RUNNING_SERVER=1 DO_GCOV="" DO_GDB="" DO_DDD="" +DO_CLIENT_GDB="" SLEEP_TIME=2 +CHARACTER_SET=latin1_de DBUSER="" while test $# -gt 0; do @@ -135,10 +139,33 @@ while test $# -gt 0; do --tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;; --master_port=*) MASTER_MYPORT=`$ECHO "$1" | $SED -e "s;--master_port=;;"` ;; --slave_port=*) SLAVE_MYPORT=`$ECHO "$1" | $SED -e "s;--slave_port=;;"` ;; + --with-openssl) + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ + --ssl-ca=$BASEDIR/SSL/cacert.pem \ + --ssl-cert=$BASEDIR/SSL/server-cert.pem \ + --ssl-key=$BASEDIR/SSL/server-key.pem" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \ + --ssl-ca=$BASEDIR/SSL/cacert.pem \ + --ssl-cert=$BASEDIR/SSL/server-cert.pem \ + --ssl-key=$BASEDIR/SSL/server-key.pem" ;; + --skip-innobase) + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;; + --skip-bdb) + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-bdb" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-bdb" ;; --skip-rpl) NO_SLAVE=1 ;; + --skip-test=*) SKIP_TEST=`$ECHO "$1" | $SED -e "s;--skip-test=;;"`;; + --do-test=*) DO_TEST=`$ECHO "$1" | $SED -e "s;--do-test=;;"`;; --record) RECORD=1; EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; + --bench) + DO_BENCH=1 + NO_SLAVE=1 + ;; + --big*) # Actually --big-test + EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; --sleep=*) EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" SLEEP_TIME=`$ECHO "$1" | $SED -e "s;--sleep=;;"` @@ -160,18 +187,22 @@ while test $# -gt 0; do ;; --gdb ) if [ x$BINARY_DIST = x1 ] ; then - $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with -gdb option" + $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --gdb option" fi DO_GDB=1 USE_RUNNING_SERVER="" - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-stack" + ;; + --client-gdb ) + if [ x$BINARY_DIST = x1 ] ; then + $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --client-gdb option" + fi + DO_CLIENT_GDB=1 ;; --ddd ) if [ x$BINARY_DIST = x1 ] ; then - $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with -gdb option" + $ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --ddd option" fi DO_DDD=1 - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-stack" USE_RUNNING_SERVER="" ;; --skip-*) @@ -180,9 +211,9 @@ while test $# -gt 0; do ;; --debug) EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ - --debug=d:t:O,$MYSQL_TMP_DIR/master.trace" + --debug=d:t:O,$MYSQL_TEST_DIR/var/log/master.trace" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \ - --debug=d:t:O,$MYSQL_TMP_DIR/slave.trace" + --debug=d:t:O,$MYSQL_TEST_DIR/var/log/slave.trace" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug" ;; -- ) shift; break ;; @@ -231,16 +262,23 @@ fi [ -z "$COLUMNS" ] && COLUMNS=80 E=`$EXPR $COLUMNS - 8` -#DASH72=`expr substr '------------------------------------------------------------------------' 1 $E` +#DASH72=`$EXPR substr '------------------------------------------------------------------------' 1 $E` DASH72=`$ECHO '------------------------------------------------------------------------'|$CUT -c 1-$E` # on source dist, we pick up freshly build executables # on binary, use what is installed if [ x$SOURCE_DIST = x1 ] ; then MYSQLD="$BASEDIR/sql/mysqld" - MYSQL_TEST="$BASEDIR/client/mysqltest" + if [ -e "$BASEDIR/client/.libs/mysqltest" ] ; then + [ -e "$BASEDIR/client/.libs/lt-mysqltest" ] || $BASEDIR/client/mysqltest -V + MYSQL_TEST="$BASEDIR/client/.libs/lt-mysqltest" + else + MYSQL_TEST="$BASEDIR/client/mysqltest" + fi MYSQLADMIN="$BASEDIR/client/mysqladmin" MYSQL="$BASEDIR/client/mysql" + LANGUAGE="$BASEDIR/sql/share/english/" + CHARSETSDIR="$BASEDIR/sql/share/charsets" INSTALL_DB="./install_test_db" else MYSQLD="$BASEDIR/bin/mysqld" @@ -248,6 +286,14 @@ else MYSQLADMIN="$BASEDIR/bin/mysqladmin" MYSQL="$BASEDIR/bin/mysql" INSTALL_DB="./install_test_db -bin" + if test -d "$BASEDIR/share/mysql/english" + then + LANGUAGE="$BASEDIR/share/mysql/english/" + CHARSETSDIR="$BASEDIR/share/mysql/charsets" + else + LANGUAGE="$BASEDIR/share/english/" + CHARSETSDIR="$BASEDIR/share/charsets" + fi fi # If we should run all tests cases, we will use a local server for that @@ -272,7 +318,10 @@ then fi -MYSQL_TEST="$MYSQL_TEST --no-defaults --socket=$MASTER_MYSOCK --database=$DB --user=$DBUSER --password=$DBPASSWD --silent -v --tmpdir=$MYSQL_TMP_DIR" +MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB --user=$DBUSER --password=$DBPASSWD --silent -v --tmpdir=$MYSQL_TMP_DIR" +MYSQL_TEST_BIN=$MYSQL_TEST +MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS" +GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave GCOV_MSG=$MYSQL_TMP_DIR/mysqld-gcov.out @@ -303,11 +352,18 @@ show_failed_diff () { reject_file=r/$1.reject result_file=r/$1.result + eval_file=r/$1.eval + + if [ -f $eval_file ] + then + result_file=$eval_file + fi + if [ -x "$DIFF" ] && [ -f $reject_file ] then echo "Below are the diffs between actual and expected results:" echo "-------------------------------------------------------" - $DIFF -c $result_file $reject_file + $DIFF -c -a $result_file $reject_file echo "-------------------------------------------------------" echo "Please follow the instructions outlined at" echo "http://www.mysql.com/doc/R/e/Reporting_mysqltest_bugs.html" @@ -315,6 +371,15 @@ show_failed_diff () fi } +do_gdb_test () +{ + mysql_test_args="$MYSQL_TEST_ARGS $1" + $ECHO "set args $mysql_test_args < $2" > $GDB_CLIENT_INIT + echo "Set breakpoints ( if needed) and type 'run' in gdb window" + #this xterm should not be backgrounded + xterm -title "Client" -e gdb -x $GDB_CLIENT_INIT $MYSQL_TEST_BIN +} + error () { $ECHO "Error: $1" exit 1 @@ -435,19 +500,40 @@ start_master() # Remove old berkeley db log files that can confuse the server $RM -f $MASTER_MYDDIR/log.* #start master - master_args="--no-defaults --log-bin=master-bin \ + if [ -z "$DO_BENCH" ] + then + master_args="--no-defaults --log-bin=master-bin \ --server-id=1 \ --basedir=$MY_BASEDIR \ --port=$MASTER_MYPORT \ + --exit-info=256 \ --datadir=$MASTER_MYDDIR \ --pid-file=$MASTER_MYPID \ --socket=$MASTER_MYSOCK \ - --log=$MASTER_MYLOG --default-character-set=latin1 \ + --log=$MASTER_MYLOG \ + --character-sets-dir=$CHARSETSDIR \ + --default-character-set=$CHARACTER_SET \ --tmpdir=$MYSQL_TMP_DIR \ - --language=english \ + --language=$LANGUAGE \ --innodb_data_file_path=ibdata1:50M \ $SMALL_SERVER \ $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT" + else + master_args="--no-defaults --log-bin=master-bin --server-id=1 \ + --basedir=$MY_BASEDIR \ + --port=$MASTER_MYPORT \ + --datadir=$MASTER_MYDDIR \ + --pid-file=$MASTER_MYPID \ + --socket=$MASTER_MYSOCK \ + --character-sets-dir=$CHARSETSDIR \ + --default-character-set=$CHARACTER_SET \ + --core \ + --tmpdir=$MYSQL_TMP_DIR \ + --language=$LANGUAGE \ + --innodb_data_file_path=ibdata1:50M \ + $SMALL_SERVER \ + $EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT" + fi if [ x$DO_DDD = x1 ] then $ECHO "set args $master_args" > $GDB_MASTER_INIT @@ -496,18 +582,23 @@ start_slave() --pid-file=$SLAVE_MYPID \ --port=$SLAVE_MYPORT \ --socket=$SLAVE_MYSOCK \ - --log=$SLAVE_MYLOG --default-character-set=latin1 \ + --log=$SLAVE_MYLOG \ + --character-sets-dir=$CHARSETSDIR \ + --default-character-set=$CHARACTER_SET \ --core \ --tmpdir=$MYSQL_TMP_DIR \ - --language=english \ + --language=$LANGUAGE \ --skip-innodb --skip-slave-start \ + --slave-load-tmpdir=$SLAVE_LOAD_TMPDIR \ + --report-host=127.0.0.1 --report-user=root \ + --report-port=$SLAVE_MYPORT \ $SMALL_SERVER \ $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT" if [ x$DO_DDD = x1 ] then $ECHO "set args $master_args" > $GDB_SLAVE_INIT ddd --debugger "gdb -x $GDB_SLAVE_INIT" $SLAVE_MYSQLD & - prompt_user "Hit enter to continue after you've started the master" + prompt_user "Hit enter to continue after you've started the slave" elif [ x$DO_GDB = x1 ] then $ECHO "set args $slave_args" > $GDB_SLAVE_INIT @@ -609,6 +700,22 @@ run_testcase () slave_init_script=$TESTDIR/$tname-slave.sh slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` + if [ -n "$SKIP_TEST" ] ; then + SKIP_THIS_TEST=`$EXPR \( $tname : "$SKIP_TEST" \) != 0` + if [ x$SKIP_THIS_TEST = x1 ] ; + then + return; + fi + fi + + if [ -n "$DO_TEST" ] ; then + DO_THIS_TEST=`$EXPR \( $tname : "$DO_TEST" \) != 0` + if [ x$DO_THIS_TEST = x0 ] ; + then + return; + fi + fi + if [ x${NO_SLAVE}x$SKIP_SLAVE = x1x0 ] ; then @@ -616,9 +723,9 @@ run_testcase () SYST=" ...." REALT=" ...." timestr="$USERT $SYST $REALT" - pname=`$ECHO "$tname "|$CUT -c 1-16` - RES="$pname $timestr" - pass_inc + pname=`$ECHO "$tname "|$CUT -c 1-24` + RES="$pname $timestr" + skip_inc $ECHO "$RES$RES_SPACE [ skipped ]" return fi @@ -672,8 +779,13 @@ run_testcase () if [ -f $tf ] ; then $RM -f r/$tname.*reject - mytime=`$TIME -p $MYSQL_TEST -R r/$tname.result $EXTRA_MYSQL_TEST_OPT \ - < $tf 2> $TIMEFILE` + mysql_test_args="-R r/$tname.result $EXTRA_MYSQL_TEST_OPT" + if [ -z "$DO_CLIENT_GDB" ] ; then + mytime=`$TIME -p $MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE` + else + do_gdb_test "$mysql_test_args" "$tf" + fi + res=$? if [ $res = 0 ]; then @@ -692,15 +804,19 @@ run_testcase () fi timestr="$USERT $SYST $REALT" - pname=`$ECHO "$tname "|$CUT -c 1-16` - RES="$pname $timestr" + pname=`$ECHO "$tname "|$CUT -c 1-24` + RES="$pname $timestr" if [ $res = 0 ]; then total_inc pass_inc $ECHO "$RES$RES_SPACE [ pass ]" else - if [ $res = 1 ]; then + # why the following ``if'' ? That is why res==1 is special ? + if [ $res = 2 ]; then + skip_inc + $ECHO "$RES$RES_SPACE [ skipped ]" + else total_inc fail_inc $ECHO "$RES$RES_SPACE [ fail ]" @@ -724,9 +840,6 @@ run_testcase () fi $ECHO "Resuming Tests" $ECHO "" - else - pass_inc - $ECHO "$RES$RES_SPACE [ skipped ]" fi fi fi @@ -763,6 +876,28 @@ fi $ECHO "Starting Tests" +if [ "$DO_BENCH" = 1 ] +then + BENCHDIR=$BASEDIR/sql-bench/ + savedir=`pwd` + cd $BENCHDIR + if [ -z "$1" ] + then + ./run-all-tests --socket=$MASTER_MYSOCK --user=root + else + if [ -x "./$1" ] + then + ./$1 --socket=$MASTER_MYSOCK --user=root + else + echo "benchmark $1 not found" + fi + fi + cd $savedir + mysql_stop + exit +fi + + $ECHO $ECHO " TEST USER SYSTEM ELAPSED RESULT" $ECHO $DASH72 diff --git a/mysql-test/r/big_test.require b/mysql-test/r/big_test.require new file mode 100644 index 00000000000..001b903496b --- /dev/null +++ b/mysql-test/r/big_test.require @@ -0,0 +1,2 @@ +using_big_test +1 diff --git a/mysql-test/r/count_distinct2.result b/mysql-test/r/count_distinct2.result new file mode 100644 index 00000000000..3586910e8b3 --- /dev/null +++ b/mysql-test/r/count_distinct2.result @@ -0,0 +1,84 @@ +n1 +1 +2 +NULL +count(distinct n1) +2 +n2 +11 +12 +13 +NULL +count(distinct n2) +3 +s +one +two +NULL +count(distinct s) +2 +vs +eleven +twevle +thirteen +NULL +count(distinct vs) +3 +t +eleven +twelve +foo +bar +NULL +count(distinct t) +4 +n1 n2 +1 11 +2 11 +2 12 +2 13 +NULL 13 +2 NULL +count(distinct n1,n2) +4 +n1 s +1 one +2 two +NULL two +2 NULL +count(distinct n1,s) +2 +s n1 vs +one 1 eleven +two 2 eleven +two 2 twevle +two 2 thirteen +two NULL thirteen +NULL 2 thirteen +two 2 NULL +count(distinct s,n1,vs) +4 +s t +one eleven +two eleven +two twelve +two foo +two bar +NULL bar +two NULL +count(distinct s,t) +5 +count(distinct n1) count(distinct n2) +2 3 +count(distinct n2) n1 +1 NULL +1 1 +3 2 +count(distinct n) +5000 +Variable_name Value +Created_tmp_disk_tables 1 +count(distinct s) +5000 +Variable_name Value +Created_tmp_disk_tables 1 diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result new file mode 100644 index 00000000000..71bed79891a --- /dev/null +++ b/mysql-test/r/ctype_latin1_de.result @@ -0,0 +1,168 @@ +a b +a 35 +ac 2 +ad 4 +ä 1 +ae 3 +ää 31 +aeae 33 +ääa 32 +aeb 6 +Äc 5 +eä 28 +o 37 +oc 15 +od 18 +ö 14 +oe 17 +Öa 16 +oeb 20 +Öc 19 +öo 30 +q 34 +s 21 +ss 22 +ß 23 +ssa 25 +ßa 27 +ßb 24 +ssc 26 +u 36 +uc 8 +ud 10 +ue 9 +Ü 11 +ueb 12 +üc 7 +uf 13 +uü 29 +é 38 +É 39 +a b +a 35 +ac 2 +ad 4 +ä 1 +ae 3 +ää 31 +aeae 33 +ääa 32 +aeb 6 +Äc 5 +eä 28 +o 37 +oc 15 +od 18 +ö 14 +oe 17 +Öa 16 +oeb 20 +Öc 19 +öo 30 +q 34 +s 21 +ss 22 +ß 23 +ssa 25 +ßa 27 +ßb 24 +ssc 26 +u 36 +uc 8 +ud 10 +ue 9 +Ü 11 +ueb 12 +üc 7 +uf 13 +uü 29 +é 38 +É 39 +a +É +é +uü +uf +üc +ueb +Ü +ue +ud +uc +u +ssc +ßb +ßa +ssa +ß +ss +s +q +öo +Öc +oeb +Öa +oe +ö +od +oc +o +eä +Äc +aeb +ääa +aeae +ää +ae +ä +ad +ac +a +Table Op Msg_type Msg_text +test.t1 check status OK +a b +Öa 16 +Öc 19 +öo 30 +a b +é 38 +É 39 +a b +a 35 +ac 2 +ad 4 +ae 3 +aeae 33 +ääa 32 +aeb 6 +Öa 16 +ssa 25 +ßa 27 +a b +u 36 +uc 8 +ud 10 +ue 9 +ueb 12 +uf 13 +uü 29 +a b +ss 22 +ssa 25 +ssc 26 +strcmp('ä','ae') strcmp('ae','ä') strcmp('aeq','äq') strcmp('äq','aeq') +0 0 0 0 +strcmp('ss','ß') strcmp('ß','ss') strcmp('ßs','sss') strcmp('ßq','ssq') +0 0 0 0 +strcmp('ä','af') strcmp('a','ä') strcmp('ää','aeq') strcmp('ää','aeaeq') +-1 -1 -1 -1 +strcmp('ss','ßa') strcmp('ß','ssa') strcmp('sßa','sssb') strcmp('s','ß') +-1 -1 -1 -1 +strcmp('ö','oö') strcmp('Ü','uü') strcmp('ö','oeb') +-1 -1 -1 +strcmp('af','ä') strcmp('ä','a') strcmp('aeq','ää') strcmp('aeaeq','ää') +1 1 1 1 +strcmp('ßa','ss') strcmp('ssa','ß') strcmp('sssb','sßa') strcmp('ß','s') +1 1 1 1 +strcmp('u','öa') strcmp('u','ö') +1 1 diff --git a/mysql-test/r/fulltext_distinct.result b/mysql-test/r/fulltext_distinct.result new file mode 100644 index 00000000000..9729eb59c10 --- /dev/null +++ b/mysql-test/r/fulltext_distinct.result @@ -0,0 +1,10 @@ +id tag value +1 foo123 bar111 +2 foo123 bar222 +3 bar345 baz333 ar +id_t2 id_t1 field_number +12346 3 1 +2231626 64280 0 +2231626 64281 0 +id_t2 +12346 diff --git a/mysql-test/r/fulltext_var.result b/mysql-test/r/fulltext_var.result new file mode 100644 index 00000000000..0352cd7addf --- /dev/null +++ b/mysql-test/r/fulltext_var.result @@ -0,0 +1,4 @@ +Variable_name Value +ft_min_word_len 4 +ft_max_word_len 254 +ft_max_word_len_for_sort 20 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 790cce9f1c1..52999dfaf10 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -27,19 +27,35 @@ DAYOFYEAR("1997-03-03") WEEK("1998-03-03") QUARTER(980303) HOUR("1997-03-03 23:03:22") MINUTE("23:03:22") SECOND(230322) 23 3 22 week(19980101) week(19970101) week(19980101,1) week(19970101,1) -0 1 1 1 +0 0 1 1 week(19981231) week(19971231) week(19981231,1) week(19971231,1) -52 53 53 53 +52 52 53 53 week(19950101) week(19950101,1) 1 0 yearweek('1981-12-31',1) yearweek('1982-01-01',1) yearweek('1982-12-31',1) yearweek('1983-01-01',1) 198153 198153 198252 198252 +yearweek('1987-01-01',1) yearweek('1987-01-01') +198701 198652 +2000 2001 2002 2003 2004 2005 2006 +0 0 0 0 0 0 1 +2000 2001 2002 2003 2004 2005 2006 +1 0 1 1 1 1 1 +2000 2001 2002 2003 2004 2005 2006 +0 1 1 1 1 0 0 +2000 2001 2002 2003 2004 2005 2006 +1 1 1 2 2 1 1 +2000 2001 2002 2003 2004 2005 2006 +199952 200053 200152 200252 200352 200452 200601 +2000 2001 2002 2003 2004 2005 2006 +200001 200053 200201 200301 200401 200501 200601 +2000 2001 2002 2003 2004 2005 2006 +199952 200101 200201 200301 200401 200453 200552 +2000 2001 2002 2003 2004 2005 2006 +200001 200101 200201 200302 200402 200501 200601 date_format('1998-12-31','%x-%v') date_format('1999-01-01','%x-%v') 1998-53 1998-53 date_format('1999-12-31','%x-%v') date_format('2000-01-01','%x-%v') 1999-52 1999-52 -yearweek('1987-01-01',1) yearweek('1987-01-01') -198701 198653 dayname("1962-03-03") dayname("1962-03-03")+0 Saturday 5 monthname("1972-03-04") monthname("1972-03-04")+0 diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result new file mode 100644 index 00000000000..5dcab296eac --- /dev/null +++ b/mysql-test/r/handler.result @@ -0,0 +1,87 @@ +a b +14 aaa +a b +15 bbb +a b +16 ccc +a b +15 bbb +a b +22 iii +a b +21 hhh +a b +20 ggg +a b +14 aaa +a b +a b +22 iii +a b +21 hhh +a b +22 iii +a b +a b +15 bbb +a b +16 ccc +a b +19 fff +a b +19 yyy +a b +19 fff +a b +a b +14 aaa +a b +18 eee +a b +18 eee +a b +19 fff +a b +18 eee +a b +17 ddd +a b +14 aaa +15 bbb +16 ccc +16 xxx +17 ddd +a b +18 eee +19 fff +19 yyy +a b +19 fff +18 eee +17 ddd +16 xxx +16 ccc +15 bbb +14 aaa +a b +16 ccc +16 xxx +17 ddd +18 eee +a b +17 ddd +18 eee +a b +22 iii +21 hhh +20 ggg +a b +19 fff +a b +19 yyy +a b +17 ddd +a b +18 eee +a b +19 fff diff --git a/mysql-test/r/have_openssl.require b/mysql-test/r/have_openssl.require new file mode 100644 index 00000000000..9bdffdf0c13 --- /dev/null +++ b/mysql-test/r/have_openssl.require @@ -0,0 +1,2 @@ +Variable_name Value +have_ssl YES diff --git a/mysql-test/r/have_openssl_1.require b/mysql-test/r/have_openssl_1.require new file mode 100644 index 00000000000..dae48a472b5 --- /dev/null +++ b/mysql-test/r/have_openssl_1.require @@ -0,0 +1,2 @@ +Variable_name Value +have_openssl YES diff --git a/mysql-test/r/have_openssl_2.require b/mysql-test/r/have_openssl_2.require new file mode 100644 index 00000000000..09a65d7d9bc --- /dev/null +++ b/mysql-test/r/have_openssl_2.require @@ -0,0 +1,2 @@ +Variable_name Value +jkhjkhfs diff --git a/mysql-test/r/have_symlink.require b/mysql-test/r/have_symlink.require new file mode 100644 index 00000000000..55ad9437034 --- /dev/null +++ b/mysql-test/r/have_symlink.require @@ -0,0 +1,2 @@ +Variable_name Value +have_symlink YES diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 913f4226f1c..67aa024b117 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -115,7 +115,7 @@ t1 index level level 1 NULL 39 where used; Using index table type possible_keys key key_len ref rows Extra t1 index level level 1 NULL 39 where used; Using index table type possible_keys key key_len ref rows Extra -t1 ref level level 1 const 12 +t1 ALL level NULL NULL NULL 39 where used level id 1 1002 1 1003 @@ -479,3 +479,5 @@ id name value uid 1 one one value 101 3 three three value 103 6 two other value 102 +a +a diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index c754085ccb3..04498add5e9 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -11,3 +11,5 @@ payoutID 19 20 22 +Variable_name Value +myisam_bulk_insert_tree_size 8388608 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result new file mode 100644 index 00000000000..6358e2a81cd --- /dev/null +++ b/mysql-test/r/multi_update.result @@ -0,0 +1,22 @@ +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +test.t3 check status OK +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 +count(*) +0 diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index ead1dc29326..87ba8961ad6 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -53,7 +53,7 @@ t1 ref a,b a 5 const 1 where used table type possible_keys key key_len ref rows Extra t1 ALL NULL NULL NULL NULL 12 where used table type possible_keys key key_len ref rows Extra -t1 range a,b a 5 NULL 12 where used +t1 range a,b a 5 NULL 5 where used table type possible_keys key key_len ref rows Extra t1 range a,b a 5 NULL 4 where used table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result new file mode 100644 index 00000000000..6636a336c45 --- /dev/null +++ b/mysql-test/r/openssl_1.result @@ -0,0 +1,16 @@ +Variable_name Value +SSL_CTX_sess_accept 0 +SSL_CTX_sess_accept_good 0 +SSL_CTX_sess_accept_renegotiate 0 +SSL_CTX_sess_cb_hits 0 +SSL_CTX_sess_number 0 +SSL_CTX_get_session_cache_mode SERVER +SSL_CTX_sess_get_cache_size 128 +SSL_CTX_get_verify_mode 7 +SSL_CTX_get_verify_depth 4294967295 +SSL_get_verify_mode 0 +SSL_get_verify_depth 0 +SSL_session_reused 0 +SSL_get_version +SSL_get_cipher +SSL_get_default_timeout 0 diff --git a/mysql-test/r/openssl_2.result b/mysql-test/r/openssl_2.result new file mode 100644 index 00000000000..6636a336c45 --- /dev/null +++ b/mysql-test/r/openssl_2.result @@ -0,0 +1,16 @@ +Variable_name Value +SSL_CTX_sess_accept 0 +SSL_CTX_sess_accept_good 0 +SSL_CTX_sess_accept_renegotiate 0 +SSL_CTX_sess_cb_hits 0 +SSL_CTX_sess_number 0 +SSL_CTX_get_session_cache_mode SERVER +SSL_CTX_sess_get_cache_size 128 +SSL_CTX_get_verify_mode 7 +SSL_CTX_get_verify_depth 4294967295 +SSL_get_verify_mode 0 +SSL_get_verify_depth 0 +SSL_session_reused 0 +SSL_get_version +SSL_get_cipher +SSL_get_default_timeout 0 diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 1a292b1203c..f6fc3b6090a 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -111,6 +111,122 @@ DateOfAction TransactionID member_id nickname voornaam 1 2 +table type possible_keys key key_len ref rows Extra +t1 range a a 20 NULL 2 where used; Using index +a b c +1 NULL b +table type possible_keys key key_len ref rows Extra +t1 range a a 4 NULL 10 where used; Using index +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 NULL +1 NULL b +1 NULL NULL +table type possible_keys key key_len ref rows Extra +t1 ref a a 4 const 5 where used; Using index; Using filesort +a b c +1 3 b +1 1 NULL +1 1 b +1 1 b +1 NULL NULL +1 NULL b +table type possible_keys key key_len ref rows Extra +t1 ref a a 9 const,const 2 where used; Using index; Using filesort +a b c +1 NULL NULL +1 NULL b +table type possible_keys key key_len ref rows Extra +t1 range a a 9 NULL 8 where used; Using index; Using filesort +table type possible_keys key key_len ref rows Extra +t1 range a a 9 NULL 5 where used; Using index +table type possible_keys key key_len ref rows Extra +t1 ref a a 9 const,const 1 where used; Using index; Using filesort +table type possible_keys key key_len ref rows Extra +t1 range a a 9 NULL 6 where used; Using index +table type possible_keys key key_len ref rows Extra +t1 range a a 9 NULL 5 where used; Using index +table type possible_keys key key_len ref rows Extra +t1 range a a 9 NULL 2 where used; Using index; Using filesort +table type possible_keys key key_len ref rows Extra +t1 index NULL a 18 NULL 11 Using index +a b c +1 0 +1 0 b +1 1 +1 1 b +1 1 b +1 3 b +2 1 a +2 1 b +2 2 a +2 2 b +2 3 c +table type possible_keys key key_len ref rows Extra +t1 index NULL a 18 NULL 11 Using index +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 +1 0 b +1 0 +table type possible_keys key key_len ref rows Extra +t1 range a a 18 NULL 3 where used; Using index +a b c +1 1 b +1 1 b +table type possible_keys key key_len ref rows Extra +t1 range a a 4 NULL 6 where used; Using index +a b c +1 1 b +1 1 b +1 1 +1 0 b +1 0 +count(*) +9 +a b c +2 3 c +2 2 b +2 2 a +2 1 b +2 1 a +1 3 b +1 1 b +1 1 b +1 1 +table type possible_keys key key_len ref rows Extra +t1 range a a 8 NULL 10 where used; Using index +a b c +2 1 b +2 1 a +1 1 b +1 1 b +1 1 +1 0 b +1 0 +table type possible_keys key key_len ref rows Extra +t1 range a a 4 NULL 5 where used; Using index +a b c +1 3 b +1 1 b +1 1 b +1 1 +1 0 b +1 0 gid sid uid 104620 5 15 103867 5 27 diff --git a/mysql-test/r/order_fill_sortbuf.result b/mysql-test/r/order_fill_sortbuf.result new file mode 100644 index 00000000000..cb3349cc433 --- /dev/null +++ b/mysql-test/r/order_fill_sortbuf.result @@ -0,0 +1,2 @@ +count(*) +4000 diff --git a/mysql-test/r/rpl000002.result b/mysql-test/r/rpl000002.result index a68ef517708..7f518a7339e 100644 --- a/mysql-test/r/rpl000002.result +++ b/mysql-test/r/rpl000002.result @@ -2,6 +2,8 @@ n 2000 2001 2002 +Server_id Host Port +2 127.0.0.1 9307 id created 1 1970-01-01 06:25:45 id created diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result index d5b4cdf3bee..74452473d0c 100644 --- a/mysql-test/r/rpl000009.result +++ b/mysql-test/r/rpl000009.result @@ -1,2 +1,32 @@ n m 4 15 +Database +bar +foo +mysql +test +Database +mysql +test +Database +bar +foo +mysql +test +Tables_in_foo +Tables_in_bar +t1 +t2 +n s +1 one bar +2 two bar +3 three bar +n s +11 eleven bar +12 twelve bar +13 thirteen bar +n s +1 one bar +2 two bar +3 three bar +4 four bar diff --git a/mysql-test/r/rpl000014.result b/mysql-test/r/rpl000014.result index a47c3c91c1d..cdafc7575ab 100644 --- a/mysql-test/r/rpl000014.result +++ b/mysql-test/r/rpl000014.result @@ -1,15 +1,15 @@ File Position Binlog_do_db Binlog_ignore_db -master-bin.001 73 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 1 master-bin.001 73 Yes 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 1 master-bin.001 73 No 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 1 master-bin.001 73 Yes 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 1 master-bin.001 173 Yes 0 0 +master-bin.001 79 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 1 master-bin.001 79 Yes 0 0 1 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 1 master-bin.001 73 No 0 0 1 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 1 master-bin.001 73 Yes 0 0 1 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 1 master-bin.001 173 Yes 0 0 1 File Position Binlog_do_db Binlog_ignore_db -master-bin.001 73 +master-bin.001 79 n 1 2 diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result index 58487af27f8..0aef660905b 100644 --- a/mysql-test/r/rpl000015.result +++ b/mysql-test/r/rpl000015.result @@ -1,13 +1,13 @@ File Position Binlog_do_db Binlog_ignore_db -master-bin.001 73 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter - 0 0 0 No 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 test 9998 60 4 No 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 4 No 0 0 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 master-bin.001 73 Yes 0 0 +master-bin.001 79 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq + 0 0 0 No 0 0 0 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 test 9998 60 4 No 0 0 0 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 60 4 No 0 0 0 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 60 master-bin.001 79 Yes 0 0 1 n 10 45 diff --git a/mysql-test/r/rpl000016.result b/mysql-test/r/rpl000016.result index abe4275a124..65f260bd575 100644 --- a/mysql-test/r/rpl000016.result +++ b/mysql-test/r/rpl000016.result @@ -1,5 +1,5 @@ -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 master-bin.001 216 Yes 0 0 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 60 master-bin.001 234 Yes 0 0 3 s Could not break slave Tried hard @@ -9,8 +9,8 @@ master-bin.002 master-bin.003 Log_name master-bin.003 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 master-bin.003 184 Yes 0 0 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 60 master-bin.003 202 Yes 0 0 3 m 34 65 @@ -23,8 +23,8 @@ master-bin.004 master-bin.005 master-bin.006 File Position Binlog_do_db Binlog_ignore_db -master-bin.006 131 -Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 master-bin.006 131 Yes 0 0 +master-bin.006 720 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root 9999 60 master-bin.006 720 Yes 0 0 11 count(*) 100 diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result new file mode 100644 index 00000000000..2090781caab --- /dev/null +++ b/mysql-test/r/rpl_log.result @@ -0,0 +1,71 @@ +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +master-bin.001 263 Query 1 5 use test; drop table t1 +master-bin.001 311 Query 1 6 use test; create table t1 (word char(20) not null) +master-bin.001 386 Create_file 1 7 db=test;table=t1;file_id=1;block_len=81 +master-bin.001 556 Exec_load 1 8 ;file_id=1 +master-bin.001 579 Query 1 9 use test; drop table t1 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +Log_name Pos Event_type Server_id Log_seq Info +master-bin.001 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 +master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +master-bin.001 172 Intvar 1 3 INSERT_ID=1 +master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) +master-bin.001 263 Query 1 5 use test; drop table t1 +master-bin.001 311 Query 1 6 use test; create table t1 (word char(20) not null) +master-bin.001 386 Create_file 1 7 db=test;table=t1;file_id=1;block_len=81 +master-bin.001 556 Exec_load 1 8 ;file_id=1 +master-bin.001 579 Query 1 9 use test; drop table t1 +master-bin.001 627 Rotate 1 10 master-bin.002;pos=4 +master-bin.001 668 Stop 1 11 +Log_name Pos Event_type Server_id Log_seq Info +master-bin.002 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 +master-bin.002 79 Query 1 2 use test; create table t1 (n int) +master-bin.002 137 Query 1 3 use test; insert into t1 values (1) +master-bin.002 197 Query 1 4 use test; drop table t1 +Log_name +master-bin.001 +master-bin.002 +Log_name +slave-bin.001 +slave-bin.002 +Log_name Pos Event_type Server_id Log_seq Info +slave-bin.001 4 Start 2 1 Server ver: $VERSION, Binlog ver: 2 +slave-bin.001 79 Slave 2 3 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.001,pos=4 +slave-bin.001 132 Query 1 2 use test; create table t1(n int not null auto_increment primary key) +slave-bin.001 225 Intvar 1 3 INSERT_ID=1 +slave-bin.001 253 Query 1 4 use test; insert into t1 values (NULL) +slave-bin.001 316 Query 1 5 use test; drop table t1 +slave-bin.001 364 Query 1 6 use test; create table t1 (word char(20) not null) +slave-bin.001 439 Create_file 1 7 db=test;table=t1;file_id=1;block_len=81 +slave-bin.001 618 Exec_load 1 8 ;file_id=1 +slave-bin.001 641 Query 1 9 use test; drop table t1 +slave-bin.001 689 Rotate 1 4 slave-bin.002;pos=4; forced by master +slave-bin.001 729 Stop 2 5 +Log_name Pos Event_type Server_id Log_seq Info +slave-bin.002 4 Start 2 1 Server ver: $VERSION, Binlog ver: 2 +slave-bin.002 79 Slave 2 10 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.002,pos=4 +slave-bin.002 132 Query 1 2 use test; create table t1 (n int) +slave-bin.002 190 Query 1 3 use test; insert into t1 values (1) +slave-bin.002 250 Query 1 4 use test; drop table t1 +Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq +127.0.0.1 root $MASTER_MYPORT 1 master-bin.002 245 Yes 0 0 4 +Log_name Log_pos +slave-bin.001 132 +Log_name Log_pos +slave-bin.001 225 +Log_name Log_pos +slave-bin.001 439 +Log_name Log_pos +slave-bin.002 132 +Log_name Log_pos +slave-bin.002 250 diff --git a/mysql-test/r/rpl_magic.result b/mysql-test/r/rpl_magic.result new file mode 100644 index 00000000000..449a6bca68c --- /dev/null +++ b/mysql-test/r/rpl_magic.result @@ -0,0 +1,22 @@ +n +1 +2 +3 +4 +5 +n +1 +2 +3 +4 +n +1 +2 +3 +4 +n +1 +2 +3 +4 +5 diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 413b03130f6..33cd9048774 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1210,7 +1210,7 @@ fld1 fld1 companynr companyname table type possible_keys key key_len ref rows Extra t2 ALL NULL NULL NULL NULL 1199 -t4 eq_ref PRIMARY PRIMARY 1 t2.companynr 1 where used; Not exists +t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 where used; Not exists table type possible_keys key key_len ref rows Extra t4 ALL NULL NULL NULL NULL 12 t2 ALL NULL NULL NULL NULL 1199 where used; Not exists diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result new file mode 100644 index 00000000000..b3fa281e76d --- /dev/null +++ b/mysql-test/r/select_found.result @@ -0,0 +1,31 @@ +a b +1 2 +2 3 +3 5 +4 5 +5 5 +6 6 +7 7 +8 9 +FOUND_ROWS() +8 +a b +1 2 +FOUND_ROWS() +8 +a b +8 9 +FOUND_ROWS() +8 +b +2 +FOUND_ROWS() +6 +b c +5 3 +FOUND_ROWS() +6 +a b a b +3 5 5 5 +FOUND_ROWS() +8 diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 099ea2fa109..a8be3f04249 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -90,3 +90,6 @@ t1 CREATE TABLE `t1` ( `a` int(11) NOT NULL default '0', PRIMARY KEY (`a`) ) TYPE=MyISAM +Database Table In_use Name_locked +Database Table In_use Name_locked +test t1 0 0 diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result new file mode 100644 index 00000000000..71e8f79b890 --- /dev/null +++ b/mysql-test/r/symlink.result @@ -0,0 +1,23 @@ +Table Op Msg_type Msg_text +test.t9 check status OK +Table Op Msg_type Msg_text +test.t9 optimize status OK +Table Op Msg_type Msg_text +test.t9 repair status OK +Table Create Table +t9 CREATE TABLE `t9` ( + `a` int(11) NOT NULL auto_increment, + `b` char(16) NOT NULL default '', + `c` int(11) NOT NULL default '0', + PRIMARY KEY (`a`) +) TYPE=MyISAM +count(*) +16724 +Table Create Table +t9 CREATE TABLE `t9` ( + `a` int(11) NOT NULL auto_increment, + `b` char(16) NOT NULL default '', + `c` int(11) NOT NULL default '0', + `d` int(11) NOT NULL default '0', + PRIMARY KEY (`a`) +) TYPE=MyISAM diff --git a/mysql-test/r/truncate.result b/mysql-test/r/truncate.result index 716b38c57c7..e091bb8c73a 100644 --- a/mysql-test/r/truncate.result +++ b/mysql-test/r/truncate.result @@ -2,3 +2,4 @@ count(*) 0 count(*) 1 +a b c1 diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 7028b5ffe33..97365811785 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -33,3 +33,5 @@ date_format(a,"%Y-%m-%d")=b right(a,6)=c+0 a=d+0 1 1 1 a 0000-00-00 00:00:00 +id dt +1 2001-08-14 00:00:00 diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result new file mode 100644 index 00000000000..31244341196 --- /dev/null +++ b/mysql-test/r/union.result @@ -0,0 +1,61 @@ +a b +1 a +2 b +3 c +4 d +5 f +6 e +a b +1 a +2 b +3 c +3 c +3 c +4 d +5 f +6 e +a b +1 a +2 b +3 c +3 c +3 c +4 d +6 e +5 f +a b +1 a +2 b +3 c +3 c +3 c +4 d +5 f +6 e +7 g +0 # +0 # +1 a +2 b +3 c +3 c +3 c +4 d +5 f +6 e +7 g +a b +1 a +2 b +3 c +t1 b count(*) +t1 a 1 +t1 b 1 +t1 c 2 +t2 c 1 +t2 d 1 +t2 e 1 +t2 f 1 +table type possible_keys key key_len ref rows Extra +t1 ALL NULL NULL NULL NULL 4 +t2 ALL NULL NULL NULL NULL 4 diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index 62aeae21970..bb4aaefe057 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -2,5 +2,9 @@ A 65 9223372036854775807 -1 0x31+1 concat(0x31)+1 -0xf 50 2 -15 +x'31' X'ffff'+0 +1 65535 table type possible_keys key key_len ref rows Extra t1 const UNIQ UNIQ 8 const 1 +x xx +1 2 diff --git a/mysql-test/std_data/master-bin.001 b/mysql-test/std_data/master-bin.001 Binary files differindex fa30d8e5302..2ec2397acdd 100644 --- a/mysql-test/std_data/master-bin.001 +++ b/mysql-test/std_data/master-bin.001 diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index dbfbd4267d8..681e3d36cca 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -73,6 +73,26 @@ OPTIMIZE TABLE t1; DROP TABLE t1; # +# ALTER TABLE ... ENABLE/DISABLE KEYS + +create table t1 (n1 int not null, n2 int, n3 int, n4 float, + unique(n1), + key (n1, n2, n3, n4), + key (n2, n3, n4, n1), + key (n3, n4, n1, n2), + key (n4, n1, n2, n3) ); +alter table t1 disable keys; +#let $1=10000; +let $1=10; +while ($1) +{ + eval insert into t1 values($1,RAND()*1000,RAND()*1000,RAND()); + dec $1; +} +alter table t1 enable keys; +drop table t1; + +# # Drop and add an auto_increment column # @@ -81,4 +101,3 @@ insert into t1 values (null),(null),(null),(null); alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); select * from t1; drop table t1; - diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index 1b5022f6e4c..3f56b3e47ce 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -2,6 +2,7 @@ # Test of procedure analyse # +drop table if exists t1,t2; create table t1 (i int, j int); insert into t1 values (1,2), (3,4), (5,6), (7,8); select * from t1 procedure analyse(); diff --git a/mysql-test/t/bdb-crash.test b/mysql-test/t/bdb-crash.test index 05ab7260d23..e2d2cd42be2 100644 --- a/mysql-test/t/bdb-crash.test +++ b/mysql-test/t/bdb-crash.test @@ -1,3 +1,4 @@ +-- source include/have_bdb.inc # test for bug reported by Mark Steele drop table if exists tblChange; diff --git a/mysql-test/t/check.test b/mysql-test/t/check.test index 62af9f92e65..6296b31d65d 100644 --- a/mysql-test/t/check.test +++ b/mysql-test/t/check.test @@ -16,3 +16,4 @@ insert into t1 values (200000); connection con1; reap; drop table t1; + diff --git a/mysql-test/t/count_distinct2-master.opt b/mysql-test/t/count_distinct2-master.opt new file mode 100644 index 00000000000..8f1be6dce3a --- /dev/null +++ b/mysql-test/t/count_distinct2-master.opt @@ -0,0 +1 @@ +-O max_heap_table_size=16384 diff --git a/mysql-test/t/count_distinct2.test b/mysql-test/t/count_distinct2.test new file mode 100644 index 00000000000..33d4cf54278 --- /dev/null +++ b/mysql-test/t/count_distinct2.test @@ -0,0 +1,74 @@ +create table t1(n1 int, n2 int, s char(20), vs varchar(20), t text); +insert into t1 values (1,11, 'one','eleven', 'eleven'), + (1,11, 'one','eleven', 'eleven'), + (2,11, 'two','eleven', 'eleven'), + (2,12, 'two','twevle', 'twelve'), + (2,13, 'two','thirteen', 'foo'), + (2,13, 'two','thirteen', 'foo'), + (2,13, 'two','thirteen', 'bar'), + (NULL,13, 'two','thirteen', 'bar'), + (2,NULL, 'two','thirteen', 'bar'), + (2,13, NULL,'thirteen', 'bar'), + (2,13, 'two',NULL, 'bar'), + (2,13, 'two','thirteen', NULL); + +select distinct n1 from t1; +select count(distinct n1) from t1; + +select distinct n2 from t1; +select count(distinct n2) from t1; + +select distinct s from t1; +select count(distinct s) from t1; + +select distinct vs from t1; +select count(distinct vs) from t1; + +select distinct t from t1; +select count(distinct t) from t1; + +select distinct n1,n2 from t1; +select count(distinct n1,n2) from t1; + +select distinct n1,s from t1; +select count(distinct n1,s) from t1; + +select distinct s,n1,vs from t1; +select count(distinct s,n1,vs) from t1; + +select distinct s,t from t1; +select count(distinct s,t) from t1; + +select count(distinct n1), count(distinct n2) from t1; + +select count(distinct n2), n1 from t1 group by n1; +drop table t1; + +# test the converstion from tree to MyISAM +create table t1 (n int default NULL); +let $1=5000; +while ($1) +{ + eval insert into t1 values($1); + dec $1; +} + +flush status; +select count(distinct n) from t1; +show status like 'Created_tmp_disk_tables'; +drop table t1; + +#test conversion from heap to MyISAM +create table t1 (s text); +let $1=5000; +while ($1) +{ + eval insert into t1 values('$1'); + dec $1; +} + +flush status; +select count(distinct s) from t1; +show status like 'Created_tmp_disk_tables'; +drop table t1; + diff --git a/mysql-test/t/ctype_latin1_de-master.opt b/mysql-test/t/ctype_latin1_de-master.opt new file mode 100644 index 00000000000..98accd58c46 --- /dev/null +++ b/mysql-test/t/ctype_latin1_de-master.opt @@ -0,0 +1 @@ +--default-character-set=latin1_de diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test new file mode 100644 index 00000000000..1df700340da --- /dev/null +++ b/mysql-test/t/ctype_latin1_de.test @@ -0,0 +1,36 @@ +# +# Test latin_de character set +# +drop table if exists t1; +create table t1 (a char (20) not null, b int not null auto_increment, index (a,b),index(b)); +insert into t1 (a) values ('ä'),('ac'),('ae'),('ad'),('Äc'),('aeb'); +insert into t1 (a) values ('üc'),('uc'),('ue'),('ud'),('Ü'),('ueb'),('uf'); +insert into t1 (a) values ('ö'),('oc'),('Öa'),('oe'),('od'),('Öc'),('oeb'); +insert into t1 (a) values ('s'),('ss'),('ß'),('ßb'),('ssa'),('ssc'),('ßa'); +insert into t1 (a) values ('eä'),('uü'),('öo'),('ää'),('ääa'),('aeae'); +insert into t1 (a) values ('q'),('a'),('u'),('o'),('é'),('É'); +select a,b from t1 order by a,b; +select a,b from t1 order by upper(a),b; +select a from t1 order by a desc; +check table t1; +select * from t1 where a like "ö%"; +select * from t1 where a like "%É%"; +select * from t1 where a like "%Á%"; +select * from t1 where a like "%U%"; +select * from t1 where a like "%ss%"; +drop table t1; + +# The following should all be true +select strcmp('ä','ae'),strcmp('ae','ä'),strcmp('aeq','äq'),strcmp('äq','aeq'); +select strcmp('ss','ß'),strcmp('ß','ss'),strcmp('ßs','sss'),strcmp('ßq','ssq'); + +# The following should all return -1 +select strcmp('ä','af'),strcmp('a','ä'),strcmp('ää','aeq'),strcmp('ää','aeaeq'); +select strcmp('ss','ßa'),strcmp('ß','ssa'),strcmp('sßa','sssb'),strcmp('s','ß'); +select strcmp('ö','oö'),strcmp('Ü','uü'),strcmp('ö','oeb'); + +# The following should all return 1 +select strcmp('af','ä'),strcmp('ä','a'),strcmp('aeq','ää'),strcmp('aeaeq','ää'); +select strcmp('ßa','ss'),strcmp('ssa','ß'),strcmp('sssb','sßa'),strcmp('ß','s'); +select strcmp('u','öa'),strcmp('u','ö'); + diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 2a45fe8253b..50a33762776 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -28,16 +28,16 @@ drop database foo; # test drop/create database and FLUSH TABLES WITH READ LOCK drop database if exists foo; flush tables with read lock; ---error 1209 +--error 1209,1218; create database foo; unlock tables; create database foo; show databases; flush tables with read lock; ---error 1208 +--error 1208,1218; drop database foo; unlock tables; drop database foo; show databases; - - +--error 1008 +drop database foo; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index eedee811f2b..e9b9bd23398 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -74,13 +74,10 @@ CREATE TABLE t3 ( --error 1210 select * from t2 where MATCH inhalt AGAINST (t2.inhalt); - --error 1210 select * from t2 where MATCH inhalt AGAINST (t2.inhalt); - --error 1191 select * from t2 where MATCH ticket AGAINST ('foobar'); - --error 1210 select * from t2,t3 where MATCH (t2.inhalt,t3.inhalt) AGAINST ('foobar'); diff --git a/mysql-test/t/fulltext_distinct.test b/mysql-test/t/fulltext_distinct.test new file mode 100644 index 00000000000..4bd88dde496 --- /dev/null +++ b/mysql-test/t/fulltext_distinct.test @@ -0,0 +1,39 @@ +# +# Test of fulltext index +# bug reported by Tibor Simko <tibor.simko@cern.ch> +# + + DROP TABLE IF EXISTS t1; + CREATE TABLE t1 ( + id mediumint unsigned NOT NULL auto_increment, + tag char(6) NOT NULL default '', + value text NOT NULL default '', + PRIMARY KEY (id), + KEY kt(tag), + KEY kv(value(15)), + FULLTEXT KEY kvf(value) + ) TYPE=MyISAM; + DROP TABLE IF EXISTS t2; + CREATE TABLE t2 ( + id_t2 mediumint unsigned NOT NULL default '0', + id_t1 mediumint unsigned NOT NULL default '0', + field_number tinyint unsigned NOT NULL default '0', + PRIMARY KEY (id_t2,id_t1,field_number), + KEY id_t1(id_t1) + ) TYPE=MyISAM; + + INSERT INTO t1 (tag,value) VALUES ('foo123','bar111'); + INSERT INTO t2 VALUES (2231626,64280,0); + INSERT INTO t1 (tag,value) VALUES ('foo123','bar222'); + INSERT INTO t2 VALUES (2231626,64281,0); +insert into t1 (tag,value) values ('bar345','baz333 ar'); +insert into t2 values (12346, 3, 1); + +select * from t1; select * from t2; + + SELECT DISTINCT t2.id_t2 + FROM t2, t1 + WHERE MATCH (t1.value) AGAINST ('baz333') + AND t1.id = t2.id_t1; + +DROP TABLE t1,t2; diff --git a/mysql-test/t/fulltext_var.test b/mysql-test/t/fulltext_var.test new file mode 100644 index 00000000000..71213d1195a --- /dev/null +++ b/mysql-test/t/fulltext_var.test @@ -0,0 +1,5 @@ +# +# Fulltext configurable parameters +# + +show variables like "ft\_%"; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index cb021d25ae3..ec1f64307e4 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -18,13 +18,23 @@ select month("1997-01-02"),year("98-02-03"),dayofyear("1997-12-31"); select month("2001-02-00"),year("2001-00-00"); select DAYOFYEAR("1997-03-03"), WEEK("1998-03-03"), QUARTER(980303); select HOUR("1997-03-03 23:03:22"), MINUTE("23:03:22"), SECOND(230322); + +# Test of week and yearweek select week(19980101),week(19970101),week(19980101,1),week(19970101,1); select week(19981231),week(19971231),week(19981231,1),week(19971231,1); select week(19950101),week(19950101,1); select yearweek('1981-12-31',1),yearweek('1982-01-01',1),yearweek('1982-12-31',1),yearweek('1983-01-01',1); +select yearweek('1987-01-01',1),yearweek('1987-01-01'); +select week("2000-01-01",0) as '2000', week("2001-01-01",0) as '2001', week("2002-01-01",0) as '2002',week("2003-01-01",0) as '2003', week("2004-01-01",0) as '2004', week("2005-01-01",0) as '2005', week("2006-01-01",0) as '2006'; +select week("2000-01-06",0) as '2000', week("2001-01-06",0) as '2001', week("2002-01-06",0) as '2002',week("2003-01-06",0) as '2003', week("2004-01-06",0) as '2004', week("2005-01-06",0) as '2005', week("2006-01-06",0) as '2006'; +select week("2000-01-01",1) as '2000', week("2001-01-01",1) as '2001', week("2002-01-01",1) as '2002',week("2003-01-01",1) as '2003', week("2004-01-01",1) as '2004', week("2005-01-01",1) as '2005', week("2006-01-01",1) as '2006'; +select week("2000-01-06",1) as '2000', week("2001-01-06",1) as '2001', week("2002-01-06",1) as '2002',week("2003-01-06",1) as '2003', week("2004-01-06",1) as '2004', week("2005-01-06",1) as '2005', week("2006-01-06",1) as '2006'; +select yearweek("2000-01-01",0) as '2000', yearweek("2001-01-01",0) as '2001', yearweek("2002-01-01",0) as '2002',yearweek("2003-01-01",0) as '2003', yearweek("2004-01-01",0) as '2004', yearweek("2005-01-01",0) as '2005', yearweek("2006-01-01",0) as '2006'; +select yearweek("2000-01-06",0) as '2000', yearweek("2001-01-06",0) as '2001', yearweek("2002-01-06",0) as '2002',yearweek("2003-01-06",0) as '2003', yearweek("2004-01-06",0) as '2004', yearweek("2005-01-06",0) as '2005', yearweek("2006-01-06",0) as '2006'; +select yearweek("2000-01-01",1) as '2000', yearweek("2001-01-01",1) as '2001', yearweek("2002-01-01",1) as '2002',yearweek("2003-01-01",1) as '2003', yearweek("2004-01-01",1) as '2004', yearweek("2005-01-01",1) as '2005', yearweek("2006-01-01",1) as '2006'; +select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', yearweek("2002-01-06",1) as '2002',yearweek("2003-01-06",1) as '2003', yearweek("2004-01-06",1) as '2004', yearweek("2005-01-06",1) as '2005', yearweek("2006-01-06",1) as '2006'; select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v'); select date_format('1999-12-31','%x-%v'),date_format('2000-01-01','%x-%v'); -select yearweek('1987-01-01',1),yearweek('1987-01-01'); select dayname("1962-03-03"),dayname("1962-03-03")+0; select monthname("1972-03-04"),monthname("1972-03-04")+0; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test new file mode 100644 index 00000000000..359c5641056 --- /dev/null +++ b/mysql-test/t/handler.test @@ -0,0 +1,65 @@ +# +# test of HANDLER ... +# + +drop table if exists t1; +create table t1 (a int, b char(10), key a(a), key b(a,b)); +insert into t1 values +(17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"), +(14,"aaa"),(15,"bbb"),(16,"ccc"),(16,"xxx"), +(20,"ggg"),(21,"hhh"),(22,"iii"); +handler t1 open as t2; +handler t2 read a first; +handler t2 read a next; +handler t2 read a next; +handler t2 read a prev; +handler t2 read a last; +handler t2 read a prev; +handler t2 read a prev; + +handler t2 read a first; +handler t2 read a prev; + +handler t2 read a last; +handler t2 read a prev; +handler t2 read a next; +handler t2 read a next; + +handler t2 read a=(15); +handler t2 read a=(16); + +!$1070 handler t2 read a=(19,"fff"); + +handler t2 read b=(19,"fff"); +handler t2 read b=(19,"yyy"); +handler t2 read b=(19); + +!$1109 handler t1 read a last; + +handler t2 read a=(11); +handler t2 read a>=(11); + +handler t2 read a=(18); +handler t2 read a>=(18); +handler t2 read a>(18); +handler t2 read a<=(18); +handler t2 read a<(18); + +handler t2 read a first limit 5; +handler t2 read a next limit 3; +handler t2 read a prev limit 10; + +handler t2 read a>=(16) limit 4; +handler t2 read a>=(16) limit 2,2; +handler t2 read a last limit 3; + +handler t2 read a=(19); +handler t2 read a=(19) where b="yyy"; + +handler t2 read first; +handler t2 read next; +handler t2 read next; +!$1064 handler t2 read last; + +handler t2 close; +drop table if exists t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 5530e2b1f54..0d2eb09eabd 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -512,3 +512,37 @@ replace into t1 (value,name,uid) values ('other value','two',102); select * from t1; drop table t1; +# +# Test DROP DATABASE +# + +create database test_$1; +create table test_$1.t1 (a int not null) type= innodb; +insert into test_$1.t1 values(1); +create table test_$1.t2 (a int not null) type= myisam; +insert into test_$1.t2 values(1); +create table test_$1.t3 (a int not null) type= heap; +insert into test_$1.t3 values(1); +commit; +drop database test_$1; +--error 12 +show tables from test_$1; + +# +# Test truncate table +# + +create table t1 (a int not null) type= innodb; +insert into t1 values(1),(2); +--error 1192 +truncate table t1; +commit; +truncate table t1; +select * from t1; +insert into t1 values(1),(2); +delete from t1; +select * from t1; +commit; +drop table t1; + + diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index cf6f41d454d..270b1cd4c79 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -10,3 +10,15 @@ insert into t1 values (a+3); insert into t1 values (4),(a+5); select * from t1; drop table t1; + +# +# Test of duplicate key values with packed keys +# + +create table t1 (id int not null auto_increment primary key, username varchar(32) not null, unique (username)); +insert into t1 values (0,"mysql"); +insert into t1 values (0,"mysql ab"); +insert into t1 values (0,"mysql a"); +insert into t1 values (0,"r1manic"); +insert into t1 values (0,"r1man"); +drop table t1; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 17ecb2d5a1f..30d3e31188c 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -10,3 +10,59 @@ insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1; insert into t2 (payoutID) SELECT payoutID+10 FROM t1; select * from t2; drop table t1,t2; +# +# bug in bulk insert optimization +# test case by Fournier Jocelyn <joc@presence-pc.com> +# + +DROP TABLE IF EXISTS crash1,crash2; +CREATE TABLE `crash1` ( + `numeropost` bigint(20) unsigned NOT NULL default '0', + `icone` tinyint(4) unsigned NOT NULL default '0', + `numreponse` bigint(20) unsigned NOT NULL auto_increment, + `contenu` text NOT NULL, + `pseudo` varchar(50) NOT NULL default '', + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `ip` bigint(11) NOT NULL default '0', + `signature` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`,`numreponse`) + ,KEY `ip` (`ip`), + KEY `date` (`date`), + KEY `pseudo` (`pseudo`), + KEY `numreponse` (`numreponse`) +) TYPE=MyISAM; + +CREATE TABLE `crash2` ( + `numeropost` bigint(20) unsigned NOT NULL default '0', + `icone` tinyint(4) unsigned NOT NULL default '0', + `numreponse` bigint(20) unsigned NOT NULL auto_increment, + `contenu` text NOT NULL, + `pseudo` varchar(50) NOT NULL default '', + `date` datetime NOT NULL default '0000-00-00 00:00:00', + `ip` bigint(11) NOT NULL default '0', + `signature` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`numeropost`,`numreponse`), + KEY `ip` (`ip`), + KEY `date` (`date`), + KEY `pseudo` (`pseudo`), + KEY `numreponse` (`numreponse`) +) TYPE=MyISAM; + +INSERT INTO crash2 +(numeropost,icone,numreponse,contenu,pseudo,date,ip,signature) VALUES +(9,1,56,'test','joce','2001-07-25 13:50:53' +,3649052399,0); + + +INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1618,icone,contenu,pseudo,date,signature,ip FROM crash2 +WHERE numeropost=9 ORDER BY numreponse ASC; + +show variables like '%bulk%'; + +INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip) +SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2 +WHERE numeropost=9 ORDER BY numreponse ASC; + +DROP TABLE IF EXISTS crash1,crash2; + diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 238dd599664..188f699cd64 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -22,7 +22,7 @@ insert into t2 select NULL,message from t1; insert into t1 select NULL,message from t2; insert into t2 select NULL,message from t1; insert into t1 select NULL,message from t2; -create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(t1,t2); +create table t3 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,test.t2); explain select * from t3 where a < 10; explain select * from t3 where a > 10 and a < 20; select * from t3 where a = 10; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test new file mode 100644 index 00000000000..7959b67ee9c --- /dev/null +++ b/mysql-test/t/multi_update.test @@ -0,0 +1,51 @@ +# +# Only run the test if we are using --big-test, because this test takes a +# long time +# +-- require r/big_test.require +eval select $BIG_TEST as using_big_test; + +drop table if exists t1,t2,t3; +create table t1(id1 int not null auto_increment primary key, t char(12)); +create table t2(id2 int not null, t char(12)); +create table t3(id3 int not null, t char(12), index(id3)); +let $1 = 10000; +while ($1) + { + let $2 = 5; + eval insert into t1(t) values ('$1'); + while ($2) + { + eval insert into t2(id2,t) values ($1,'$2'); + let $3 = 10; + while ($3) + { + eval insert into t3(id3,t) values ($1,'$2'); + dec $3; + } + dec $2; + } + dec $1; + } + +delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 9500; + +check table t1, t2, t3; + +select count(*) from t1 where id1 > 9500; +select count(*) from t2 where id2 > 9500; +select count(*) from t3 where id3 > 9500; + +delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 500; +select count(*) from t1 where id1 > 500; +select count(*) from t2 where id2 > 500; +select count(*) from t3 where id3 > 500; + +delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0; + +# These queries will force a scan of the table +select count(*) from t1 where id1; +select count(*) from t2 where id2; +select count(*) from t3 where id3; + +drop table t1,t2,t3; diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test new file mode 100644 index 00000000000..8dfd0d8c2f9 --- /dev/null +++ b/mysql-test/t/openssl_1.test @@ -0,0 +1,6 @@ +# We test openssl. Result set is optimized to be compiled with --with-openssl but +# SSL is swithced off in some reason +-- source include/have_openssl_2.inc + +SHOW STATUS LIKE 'SSL%'; + diff --git a/mysql-test/t/openssl_2.test b/mysql-test/t/openssl_2.test new file mode 100644 index 00000000000..12f1240f3af --- /dev/null +++ b/mysql-test/t/openssl_2.test @@ -0,0 +1,5 @@ +# We want to test everything with SSL turned on. +-- source include/have_openssl_2.inc + +SHOW STATUS LIKE 'SSL%'; + diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 16094206745..baa3fe67f0b 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -206,8 +206,53 @@ ORDER by lastchange_datum DESC LIMIT 2; drop table t1; # -# Test optimizing bug with EQ_REF tables, where some ORDER BY parts where -# wrongly removed. +# Test optimization of ORDER BY DESC +# + +create table t1 (a int not null, b int, c varchar(10), key (a, b, c)); +insert into t1 values (1, NULL, NULL), (1, NULL, 'b'), (1, 1, NULL), (1, 1, 'b'), (1, 1, 'b'), (2, 1, 'a'), (2, 1, 'b'), (2, 2, 'a'), (2, 2, 'b'), (2, 3, 'c'),(1,3,'b'); + +explain select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc; +explain select * from t1 where a >= 1 and a < 3 order by a desc; +select * from t1 where a >= 1 and a < 3 order by a desc; +explain select * from t1 where a = 1 order by a desc, b desc; +select * from t1 where a = 1 order by a desc, b desc; +explain select * from t1 where a = 1 and b is null order by a desc, b desc; +select * from t1 where a = 1 and b is null order by a desc, b desc; +explain select * from t1 where a >= 1 and a < 3 and b >0 order by a desc,b desc; +explain select * from t1 where a = 2 and b >0 order by a desc,b desc; +explain select * from t1 where a = 2 and b is null order by a desc,b desc; +explain select * from t1 where a = 2 and (b is null or b > 0) order by a +desc,b desc; +explain select * from t1 where a = 2 and b > 0 order by a desc,b desc; +explain select * from t1 where a = 2 and b < 2 order by a desc,b desc; + +# +# Test things when we don't have NULL keys +# + +alter table t1 modify b int not null, modify c varchar(10) not null; +explain select * from t1 order by a, b, c; +select * from t1 order by a, b, c; +explain select * from t1 order by a desc, b desc, c desc; +select * from t1 order by a desc, b desc, c desc; +# test multiple ranges, NO_MAX_RANGE and EQ_RANGE +explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc; +# test NEAR_MAX, NO_MIN_RANGE +explain select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +select * from t1 where a < 2 and b <= 1 order by a desc, b desc; +select count(*) from t1 where a < 5 and b > 0; +select * from t1 where a < 5 and b > 0 order by a desc,b desc; +# test HA_READ_AFTER_KEY (at the end of the file), NEAR_MIN +explain select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +select * from t1 where a between 1 and 3 and b <= 1 order by a desc, b desc; +# test HA_READ_AFTER_KEY (in the middle of the file) +explain select * from t1 where a between 0 and 1 order by a desc, b desc; +select * from t1 where a between 0 and 1 order by a desc, b desc; +drop table t1; + CREATE TABLE t1 ( gid int(10) unsigned NOT NULL auto_increment, diff --git a/mysql-test/t/order_fill_sortbuf-master.opt b/mysql-test/t/order_fill_sortbuf-master.opt new file mode 100644 index 00000000000..af4e7d33143 --- /dev/null +++ b/mysql-test/t/order_fill_sortbuf-master.opt @@ -0,0 +1 @@ +-O sort_buffer=0 diff --git a/mysql-test/t/order_fill_sortbuf.test b/mysql-test/t/order_fill_sortbuf.test new file mode 100644 index 00000000000..a64ffce08e3 --- /dev/null +++ b/mysql-test/t/order_fill_sortbuf.test @@ -0,0 +1,20 @@ +# +# This test does a create-select with ORDER BY, where there is so many +# rows MySQL needs to use a merge during the sort phase. +# + +drop table if exists t1,t2; +CREATE TABLE `t1` ( + `id` int(11) NOT NULL default '0', + `id2` int(11) NOT NULL default '0', + `id3` int(11) NOT NULL default '0'); +let $1=4000; +while ($1) + { + eval insert into t1 (id,id2,id3) values ($1,$1,$1); + dec $1; + } + +create table t2 select id2 from t1 order by id3; +select count(*) from t2; +drop table t1,t2; diff --git a/mysql-test/t/rpl000002.test b/mysql-test/t/rpl000002.test index 0c490e6316d..865aa5e5bab 100644 --- a/mysql-test/t/rpl000002.test +++ b/mysql-test/t/rpl000002.test @@ -11,6 +11,7 @@ use test; sync_with_master; select * from t1; connection master; +show slave hosts; drop table t1; save_master_pos; connection slave; diff --git a/mysql-test/t/rpl000009.test b/mysql-test/t/rpl000009.test index 768c6c151b4..208e6f0b037 100644 --- a/mysql-test/t/rpl000009.test +++ b/mysql-test/t/rpl000009.test @@ -31,3 +31,56 @@ connection slave; sync_with_master; drop database if exists bar; drop database if exists foo; + +#now let's test load data from master + +#first create some databases and tables on the master +connection master; +set sql_log_bin = 0; +create database foo; +create database bar; +show databases; +create table foo.t1(n int, s char(20)); +create table foo.t2(n int, s text); +insert into foo.t1 values (1, 'one'), (2, 'two'), (3, 'three'); +insert into foo.t2 values (11, 'eleven'), (12, 'twelve'), (13, 'thirteen'); + +create table bar.t1(n int, s char(20)); +create table bar.t2(n int, s text); +insert into bar.t1 values (1, 'one bar'), (2, 'two bar'), (3, 'three bar'); +insert into bar.t2 values (11, 'eleven bar'), (12, 'twelve bar'), + (13, 'thirteen bar'); +set sql_log_bin = 1; +save_master_pos; +connection slave; +sync_with_master; + +#this should show that the slave is empty at this point +show databases; +load data from master; + +#now let's check if we have the right tables and the right data in them +show databases; +use foo; +show tables; +use bar; +show tables; +select * from bar.t1; +select * from bar.t2; + +#now let's see if replication works +connection master; +insert into bar.t1 values (4, 'four bar'); +save_master_pos; +connection slave; +sync_with_master; +select * from bar.t1; + +#now time for cleanup +connection master; +drop database bar; +drop database foo; +save_master_pos; +connection slave; +sync_with_master; + diff --git a/mysql-test/t/rpl000014.test b/mysql-test/t/rpl000014.test index b501d63b10e..604e614b3a8 100644 --- a/mysql-test/t/rpl000014.test +++ b/mysql-test/t/rpl000014.test @@ -25,7 +25,7 @@ create table foo (n int); insert into foo values (1),(2),(3); save_master_pos; connection slave; -change master to master_log_pos=73; +change master to master_log_pos=79; sync_with_master; select * from foo; connection master; diff --git a/mysql-test/t/rpl000017-slave.sh b/mysql-test/t/rpl000017-slave.sh index 4415f093aad..2ead2021416 100755 --- a/mysql-test/t/rpl000017-slave.sh +++ b/mysql-test/t/rpl000017-slave.sh @@ -6,4 +6,5 @@ replicate aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 9306 1 +0 EOF diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test new file mode 100644 index 00000000000..426553b4bdc --- /dev/null +++ b/mysql-test/t/rpl_log.test @@ -0,0 +1,48 @@ +source include/master-slave.inc; +eval_result; #result depends on some server specific params + +#clean up slave binlogs +connection slave; +slave stop; +reset master; +reset slave; + +connection master; +reset master; +drop table if exists t1; +create table t1(n int not null auto_increment primary key); +insert into t1 values (NULL); +drop table t1; +create table t1 (word char(20) not null); +load data infile '../../std_data/words.dat' into table t1; +drop table t1; +show binlog events; +show binlog events from 79 limit 1; +show binlog events from 79 limit 2; +show binlog events from 79 limit 2,1; +flush logs; +create table t1 (n int); +insert into t1 values (1); +drop table t1; +show binlog events; +show binlog events in 'master-bin.002'; +show master logs; +save_master_pos; +connection slave; +let $VERSION=`select version()`; +slave start; +sync_with_master; +show master logs; +show binlog events in 'slave-bin.001' from 4; +show binlog events in 'slave-bin.002' from 4; +show slave status; +show new master for slave with master_log_file='master-bin.001' and + master_log_pos=4 and master_log_seq=1 and master_server_id=1; +show new master for slave with master_log_file='master-bin.001' and + master_log_pos=79 and master_log_seq=2 and master_server_id=1; +show new master for slave with master_log_file='master-bin.001' and + master_log_pos=311 and master_log_seq=6 and master_server_id=1; +show new master for slave with master_log_file='master-bin.002' and + master_log_pos=4 and master_log_seq=1 and master_server_id=1; +show new master for slave with master_log_file='master-bin.002' and + master_log_pos=137 and master_log_seq=3 and master_server_id=1; diff --git a/mysql-test/t/rpl_magic.test b/mysql-test/t/rpl_magic.test new file mode 100644 index 00000000000..376edc301d7 --- /dev/null +++ b/mysql-test/t/rpl_magic.test @@ -0,0 +1,31 @@ +source include/master-slave.inc; + +#first, make sure the slave has had enough time to register +connection master; +save_master_pos; +connection slave; +sync_with_master; + +#discover slaves +connection master; +rpl_probe; + +#turn on master/slave query direction auto-magic +enable_rpl_parse; +drop table if exists t1; +create table t1 ( n int); +insert into t1 values (1),(2),(3),(4); +disable_rpl_parse; +save_master_pos; +enable_rpl_parse; +connection slave; +sync_with_master; +insert into t1 values(5); +connection master; +select * from t1; +select * from t1; +disable_rpl_parse; +select * from t1; +connection slave; +select * from t1; +drop table t1; diff --git a/mysql-test/t/rpl_mystery22.test b/mysql-test/t/rpl_mystery22.test index 3a48ef84dc1..e987074697b 100644 --- a/mysql-test/t/rpl_mystery22.test +++ b/mysql-test/t/rpl_mystery22.test @@ -1,5 +1,6 @@ # test case to make slave thread get ahead by 22 bytes +drop table if exists t1; source include/master-slave.inc; connection master; # first, cause a duplicate key problem on the slave diff --git a/mysql-test/t/rpl_sporadic_master.test b/mysql-test/t/rpl_sporadic_master.test index c1a47781ddf..0487f868436 100644 --- a/mysql-test/t/rpl_sporadic_master.test +++ b/mysql-test/t/rpl_sporadic_master.test @@ -7,7 +7,7 @@ drop table if exists t1,t2; create table t2(n int); create table t1(n int not null auto_increment primary key); insert into t1 values (NULL),(NULL); -delete from t1; +truncate table t1; # We have to use 4 in the following to make this test work with all table types insert into t1 values (4),(NULL); save_master_pos; @@ -18,10 +18,8 @@ slave start; connection master; insert into t1 values (NULL),(NULL); flush logs; -delete from t1; -insert into t1 values (10),(NULL); -insert into t1 values (NULL),(NULL); -insert into t1 values (NULL),(NULL); +truncate table t1; +insert into t1 values (10),(NULL),(NULL),(NULL),(NULL),(NULL); save_master_pos; connection slave; sync_with_master; diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test new file mode 100644 index 00000000000..52c8039b2f5 --- /dev/null +++ b/mysql-test/t/select_found.test @@ -0,0 +1,20 @@ +# +# Testing of found_rows() +# + +drop table if exists t1; +create table t1 (a int not null auto_increment, b int not null, primary key(a)); +insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9); +select SQL_CALC_FOUND_ROWS * from t1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS distinct b from t1 limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS b,count(*) as c from t1 group by b order by c desc limit 1; +select found_rows(); +select SQL_CALC_FOUND_ROWS * from t1 left join t1 as t2 on (t1.b=t2.a) limit 2,1; +select found_rows(); +drop table t1; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 0f07d577c0c..0e0d79e7d16 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -72,3 +72,10 @@ drop table t1; create table t1 (a int not null, primary key (a)); show create table t1; drop table t1; + +flush tables; +show open tables; +create table t1(n int); +insert into t1 values (1); +show open tables; +drop table t1; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 70a7a3ab584..bdfeb26073f 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -6,7 +6,7 @@ show status like 'Table_lock%'; connection con1; SET SQL_LOG_BIN=0; drop table if exists t1; -create table t1(n int); +create table t1(n int) type=myisam; insert into t1 values(1); connection con2; lock tables t1 read; diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test new file mode 100644 index 00000000000..5e2b8232844 --- /dev/null +++ b/mysql-test/t/symlink.test @@ -0,0 +1,82 @@ +-- require r/have_symlink.require +show variables like "have_symlink"; + +# +# First create little data to play with +# +drop table if exists t1,t2,t7,t8,t9; +create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)); +create table t2 (a int not null auto_increment, b char(16) not null, primary key (a)); +insert into t1 (b) values ("test"),("test1"),("test2"),("test3"); +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (b) select b from t1; +insert into t1 (b) select b from t2; +drop table t2; + +# +# Start the test +# We use t9 here to not crash with tables generated by the backup test +# + +eval create table t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp" index directory="$MYSQL_TEST_DIR/var/run"; +insert into t9 select * from t1; +check table t9; +optimize table t9; +repair table t9; +alter table t9 add column c int not null; +show create table t9; + +# Test renames +alter table t9 rename t8, add column d int not null; +alter table t8 rename t7; +rename table t7 to t9; +# Drop old t1 table, keep t9 +drop table t1; + +# +# Test error handling +# Note that we are using the above table t9 here! +# + +--error 1103 +create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="tmp"; + +# Check that we cannot link over a table from another database. + +drop database if exists test_mysqltest; +create database test_mysqltest; + +--error 1 +create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist"; + +--error 1103 +create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path"; + +--error 1 +eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run"; + +--error 1 +eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp"; + +# Check moving table t9 from default database to test_mysqltest; +# In this case the symlinks should be removed. + +alter table t9 rename test_mysqltest.t9; +select count(*) from test_mysqltest.t9; +show create table test_mysqltest.t9; +drop database test_mysqltest; diff --git a/mysql-test/t/truncate.test b/mysql-test/t/truncate.test index e995517cf1e..2430682a93f 100644 --- a/mysql-test/t/truncate.test +++ b/mysql-test/t/truncate.test @@ -2,10 +2,14 @@ # Test of truncate # create table t1 (a integer, b integer,c1 CHAR(10)); +insert into t1 (a) values (1),(2); truncate table t1; select count(*) from t1; insert into t1 values(1,2,"test"); select count(*) from t1; +delete from t1; +select * from t1; drop table t1; # The following should fail -!$1146 select count(*) from t1; +--error 1146 +select count(*) from t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 1e7bd11bab1..857937fd90e 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -30,3 +30,12 @@ CREATE TABLE t1 (a datetime not null); insert into t1 values (0); select * from t1 where a is null; drop table t1; + +# +# Test with bug when propagating DATETIME to integer and WHERE optimization +# + +create table t1 (id int, dt datetime); +insert into t1 values (1,"2001-08-14 00:00:00"),(2,"2001-08-15 00:00:00"),(3,"2001-08-16 00:00:00"); +select * from t1 where dt='2001-08-14 00:00:00' and dt = if(id=1,'2001-08-14 00:00:00','1999-08-15'); +drop table t1; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test new file mode 100644 index 00000000000..c3a0e1ef901 --- /dev/null +++ b/mysql-test/t/union.test @@ -0,0 +1,42 @@ +# +# Test of unions +# + +drop table if exists t1,t2,t3; +CREATE TABLE t1 (a int not null, b char (10) not null); +insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); +CREATE TABLE t2 (a int not null, b char (10) not null); +insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); + +select a,b from t1 union select a,b from t2; +select a,b from t1 union all select a,b from t2; +select a,b from t1 union all select a,b from t2 order by b; +select a,b from t1 union all select a,b from t2 union select 7,'g'; +select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg'; +select a,b from t1 union select a,b from t1; +select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b; + +# Test some error conditions with UNION +explain select a,b from t1 union all select a,b from t2; + +--error 1215 +select a,b from t1 into outfile 'skr' union select a,b from t2; + +--error 1215 +select a,b from t1 order by a union select a,b from t2; + +--error 1216 +create table t3 select a,b from t1 union select a from t2; + +--error 1215 +insert into t3 select a from t1 order by a union select a from t2; + +--error 1216 +select a,b from t1 union select a from t2; + +# Test CREATE, INSERT and REPLACE +create table t3 select a,b from t1 union all select a,b from t2; +insert into t3 select a,b from t1 union all select a,b from t2; +replace into t3 select a,b as c from t1 union all select a,b from t2; + +drop table t1,t2,t3; diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test index 0ab26f51e65..6d2660271ea 100644 --- a/mysql-test/t/varbinary.test +++ b/mysql-test/t/varbinary.test @@ -4,6 +4,7 @@ select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ; select 0x31+1,concat(0x31)+1,-0xf; +select x'31',X'ffff'+0; # # Test of hex constants in WHERE: @@ -14,3 +15,18 @@ insert into t1 set UNIQ=0x38afba1d73e6a18a; insert into t1 set UNIQ=123; explain select * from t1 where UNIQ=0x38afba1d73e6a18a; drop table t1; + +# +# Test error conditions +# +--error 1064 +select x'hello'; +--error 1054 +select 0xfg; + +# +# Test likely error conditions +# +create table t1 select 1 as x, 2 as xx; +select x,xx from t1; +drop table t1; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 6dd9bb06fe9..9a44d569e45 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -24,7 +24,7 @@ LDADD = libmysys.a ../dbug/libdbug.a \ noinst_HEADERS = mysys_priv.h my_static.h libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ mf_path.c mf_loadpath.c\ - my_open.c my_create.c my_seek.c my_read.c \ + my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_pread.c my_write.c \ mf_keycache.c \ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ diff --git a/mysys/hash.c b/mysys/hash.c index c05379ef4ce..acb5a9b4310 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -148,9 +148,7 @@ static uint calc_hashnr_caseup(const byte *key,uint length) * * The magic is in the interesting relationship between the special prime * 16777619 (2^24 + 403) and 2^32 and 2^8. - * - * This hash produces the fewest collisions of any function that we've seen so - * far, and works well on both numbers and strings. + * This works well on both numbers and strings. */ uint calc_hashnr(const byte *key, uint len) @@ -517,8 +515,8 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length) /* Search after record with key */ idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ? - old_key_length : - hash->key_length)), + old_key_length : + hash->key_length)), blength,records); new_index=hash_mask(rec_hashnr(hash,record),blength,records); if (idx == new_index) @@ -578,6 +576,17 @@ byte *hash_element(HASH *hash,uint idx) } +/* + Replace old row with new row. This should only be used when key + isn't changed +*/ + +void hash_replace(HASH *hash, uint idx, byte *new_row) +{ + dynamic_element(&hash->array,idx,HASH_LINK*)->data=new_row; +} + + #ifndef DBUG_OFF my_bool hash_check(HASH *hash) diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c index ff29926ac50..4b8fc6fed17 100644 --- a/mysys/mf_cache.c +++ b/mysys/mf_cache.c @@ -28,7 +28,8 @@ this, just remember the file name for later removal */ -static my_bool cache_remove_open_tmp(IO_CACHE *cache, const char *name) +static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)), + const char *name) { #if O_TEMPORARY == 0 #if !defined(CANT_DELETE_OPEN_FILES) diff --git a/mysys/mf_casecnv.c b/mysys/mf_casecnv.c index 4ec3b66d9cb..125f54b2594 100644 --- a/mysys/mf_casecnv.c +++ b/mysys/mf_casecnv.c @@ -25,6 +25,7 @@ #include "mysys_priv.h" #include <m_ctype.h> +#include <m_string.h> /* string to uppercase */ diff --git a/mysys/mf_format.c b/mysys/mf_format.c index 7dac46cf0d0..5063d6ca831 100644 --- a/mysys/mf_format.c +++ b/mysys/mf_format.c @@ -17,10 +17,6 @@ #include "mysys_priv.h" #include <m_string.h> -#ifdef HAVE_REALPATH -#include <sys/param.h> -#include <sys/stat.h> -#endif /* format a filename with replace of library and extension */ /* params to and name may be identicall */ @@ -33,21 +29,12 @@ /* 32 Resolve filename to full path */ /* 64 Return NULL if too long path */ -#ifdef SCO -#define BUFF_LEN 4097 -#else -#ifdef MAXPATHLEN -#define BUFF_LEN MAXPATHLEN -#else -#define BUFF_LEN FN_LEN -#endif -#endif my_string fn_format(my_string to, const char *name, const char *dsk, const char *form, int flag) { reg1 uint length; - char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos; + char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos; const char *ext; DBUG_ENTER("fn_format"); DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d", @@ -109,18 +96,13 @@ my_string fn_format(my_string to, const char *name, const char *dsk, #endif (void) strmov(pos,ext); /* Don't convert extension */ } - /* Purify gives a lot of UMR errors when using realpath */ -#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) - if (flag & 16) + if (flag & 32) + (void) my_realpath(to, to, MYF(flag & 32 ? 0 : MY_RESOLVE_LINK)); + else if (flag & 16) { - struct stat stat_buff; - if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode))) - { - if (realpath(to,buff)) - strmake(to,buff,FN_REFLEN-1); - } + strmov(buff,to); + (void) my_readlink(to, buff, MYF(0)); } -#endif DBUG_RETURN (to); } /* fn_format */ diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 0d1c227c2b2..0ef496227b6 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -56,6 +56,8 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize, DBUG_PRINT("enter",("type: %d pos: %ld",(int) type, (ulong) seek_offset)); info->file=file; + info->pre_close = info->pre_read = info->post_read = 0; + info->arg = 0; if (!cachesize) if (! (cachesize= my_default_record_cache_size)) DBUG_RETURN(1); /* No cache requested */ @@ -467,8 +469,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) int _my_b_get(IO_CACHE *info) { byte buff; + IO_CACHE_CALLBACK pre_read,post_read; + if ((pre_read = info->pre_read)) + (*pre_read)(info); if ((*(info)->read_function)(info,&buff,1)) return my_b_EOF; + if ((post_read = info->post_read)) + (*post_read)(info); return (int) (uchar) buff; } @@ -602,7 +609,10 @@ int flush_io_cache(IO_CACHE *info) int end_io_cache(IO_CACHE *info) { int error=0; + IO_CACHE_CALLBACK pre_close; DBUG_ENTER("end_io_cache"); + if((pre_close=info->pre_close)) + (*pre_close)(info); if (info->buffer) { if (info->file != -1) /* File doesn't exist */ @@ -612,3 +622,4 @@ int end_io_cache(IO_CACHE *info) } DBUG_RETURN(error); } /* end_io_cache */ + diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index b442af7e9e5..62394050261 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -40,6 +40,7 @@ void pack_dirname(my_string to, const char *from) char buff[FN_REFLEN]; DBUG_ENTER("pack_dirname"); + LINT_INIT(buff_length); (void) intern_filename(to,from); /* Change to intern name */ #ifdef FN_DEVCHAR @@ -49,7 +50,6 @@ void pack_dirname(my_string to, const char *from) #endif start=to; - LINT_INIT(buff_length); if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0)))) { buff_length= (uint) strlen(buff); diff --git a/mysys/mf_qsort.c b/mysys/mf_qsort.c index 032a1a28a72..3db6fae0520 100644 --- a/mysys/mf_qsort.c +++ b/mysys/mf_qsort.c @@ -1,248 +1,216 @@ -/* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Written by Douglas C. Schmidt (schmidt@ics.uci.edu). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 Library General Public License for more details. - + You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ /* - Modifications by monty: - - Uses mysys include files - - Small fixes to make the it a bit faster - - Can be compiled with a cmp function that takes one extra argument. + qsort implementation optimized for comparison of pointers + Inspired by the qsort implementations by Douglas C. Schmidt, + and Bentley & McIlroy's "Engineering a Sort Function". */ + #include "mysys_priv.h" +#include "m_string.h" -/* Envoke the comparison function, returns either 0, < 0, or > 0. */ +/* We need to use qsort with 2 different compare functions */ #ifdef QSORT_EXTRA_CMP_ARGUMENT #define CMP(A,B) ((*cmp)(cmp_argument,(A),(B))) #else #define CMP(A,B) ((*cmp)((A),(B))) #endif -/* Byte-wise swap two items of size SIZE. */ -#define SWAP(a, b, size) \ - do \ - { \ - register size_t __size = (size); \ - register char *__a = (a), *__b = (b); \ - do \ - { \ - char __tmp = *__a; \ - *__a++ = *__b; \ - *__b++ = __tmp; \ - } while (--__size > 0); \ - } while (0) - -/* Discontinue quicksort algorithm when partition gets below this size. - This particular magic number was chosen to work best on a Sun 4/260. */ -#define MAX_THRESH 8 - -/* Stack node declarations used to store unfulfilled partition obligations. */ -typedef struct _qsort_stack_node - { - char *lo; - char *hi; - } stack_node; - -/* The next 4 #defines implement a very fast in-line stack abstraction. */ -#define STACK_SIZE (8 * sizeof(unsigned long int)) -#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0) -#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0) -#define STACK_NOT_EMPTY (stack < top) - -/* Order size using quicksort. This implementation incorporates - four optimizations discussed in Sedgewick: - - 1. Non-recursive, using an explicit stack of pointer that store the - next array partition to sort. To save time, this maximum amount - of space required to store an array of MAX_INT is allocated on the - stack. Assuming a 32-bit integer, this needs only 32 * - sizeof (stack_node) == 136 bits. Pretty cheap, actually. +#define SWAP(A, B, size,swap_ptrs) \ +do { \ + if (swap_ptrs) \ + { \ + reg1 char **a = (char**) (A), **b = (char**) (B); \ + char *tmp = *a; *a++ = *b; *b++ = tmp; \ + } \ + else \ + { \ + reg1 char *a = (A), *b = (B); \ + reg3 char *end= a+size; \ + do \ + { \ + char tmp = *a; *a++ = *b; *b++ = tmp; \ + } while (a < end); \ + } \ +} while (0) + +/* Put the median in the middle argument */ +#define MEDIAN(low, mid, high) \ +{ \ + if (CMP(high,low) < 0) \ + SWAP(high, low, size, ptr_cmp); \ + if (CMP(mid, low) < 0) \ + SWAP(mid, low, size, ptr_cmp); \ + else if (CMP(high, mid) < 0) \ + SWAP(mid, high, size, ptr_cmp); \ +} - 2. Chose the pivot element using a median-of-three decision tree. - This reduces the probability of selecting a bad pivot value and - eliminates certain extraneous comparisons. +/* The following node is used to store ranges to avoid recursive calls */ - 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving - insertion sort to order the MAX_THRESH items within each partition. - This is a big win, since insertion sort is faster for small, mostly - sorted array segments. +typedef struct st_stack +{ + char *low,*high; +} stack_node; - 4. The larger of the two sub-partitions is always pushed onto the - stack first, with the algorithm then concentrating on the - smaller partition. This *guarantees* no more than log (n) - stack size is needed (actually O(1) in this case)! */ +#define PUSH(LOW,HIGH) {stack_ptr->low = LOW; stack_ptr++->high = HIGH;} +#define POP(LOW,HIGH) {LOW = (--stack_ptr)->low; HIGH = stack_ptr->high;} +/* The following stack size is enough for ulong ~0 elements */ +#define STACK_SIZE (8 * sizeof(unsigned long int)) +#define THRESHOLD_FOR_INSERT_SORT 10 #if defined(QSORT_TYPE_IS_VOID) #define SORT_RETURN return #else #define SORT_RETURN return 0 #endif +/**************************************************************************** +** 'standard' quicksort with the following extensions: +** +** Can be compiled with the qsort2_cmp compare function +** Store ranges on stack to avoid recursion +** Use insert sort on small ranges +** Optimize for sorting of pointers (used often by MySQL) +** Use median comparison to find partition element +*****************************************************************************/ + #ifdef QSORT_EXTRA_CMP_ARGUMENT -qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, qsort2_cmp cmp, +qsort_t qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp, void *cmp_argument) #else -qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp) +qsort_t qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp) #endif { - /* Allocating SIZE bytes for a pivot buffer facilitates a better - algorithm below since we can do comparisons directly on the pivot. - */ - size_t max_thresh = (size_t) (MAX_THRESH * size); - if (total_elems <= 1) - SORT_RETURN; /* Crashes on MSDOS if continues */ - - if (total_elems > MAX_THRESH) - { - char *lo = (char*) base_ptr; - char *hi = &lo[size * (total_elems - 1)]; - stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */ - stack_node *top = stack + 1; - char *pivot = (char *) my_alloca ((int) size); + char *low, *high, *pivot; + stack_node stack[STACK_SIZE], *stack_ptr; + my_bool ptr_cmp; + /* Handle the simple case first */ + /* This will also make the rest of the code simpler */ + if (count <= 1) + SORT_RETURN; + + low = (char*) base_ptr; + high = low+ size * (count - 1); + stack_ptr = stack + 1; #ifdef HAVE_purify - stack[0].lo=stack[0].hi=0; + /* The first element in the stack will be accessed for the last POP */ + stack[0].low=stack[0].high=0; #endif + pivot = (char *) my_alloca((int) size); + ptr_cmp= size == sizeof(char*) && !((low - (char*) 0)& (sizeof(char*)-1)); - do + /* The following loop sorts elements between high and low */ + do + { + char *low_ptr, *high_ptr, *mid; + + count=((size_t) (high - low) / size)+1; + /* If count is small, then an insert sort is faster than qsort */ + if (count < THRESHOLD_FOR_INSERT_SORT) { - char *left_ptr,*right_ptr; - - /* Select median value from among LO, MID, and HI. Rearrange - LO and HI so the three values are sorted. This lowers the - probability of picking a pathological pivot value and - skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ - - char *mid = lo + size * (((ulong) (hi - lo) / (ulong) size) >> 1); - - if (CMP(hi,lo) < 0) - SWAP (hi, lo, size); - if (CMP (mid, lo) < 0) - SWAP (mid, lo, size); - else if (CMP (hi, mid) < 0) - SWAP (mid, hi, size); - memcpy (pivot, mid, size); - - left_ptr = lo + size; - right_ptr = hi - size; - - /* Here's the famous ``collapse the walls'' section of quicksort. - Gotta like those tight inner loops! They are the main reason - that this algorithm runs much faster than others. */ - do + for (low_ptr = low + size; low_ptr <= high; low_ptr += size) { - while (CMP (left_ptr, pivot) < 0) - left_ptr += size; - - while (CMP (pivot, right_ptr) < 0) - right_ptr -= size; - - if (left_ptr < right_ptr) - { - SWAP (left_ptr, right_ptr, size); - left_ptr += size; - right_ptr -= size; - } - else if (left_ptr == right_ptr) - { - left_ptr += size; - right_ptr -= size; - break; - } - else - break; /* left_ptr > right_ptr */ + char *ptr; + for (ptr = low_ptr; ptr > low && CMP(ptr - size, ptr) > 0; + ptr -= size) + SWAP(ptr, ptr - size, size, ptr_cmp); } - while (left_ptr <= right_ptr); + POP(low, high); + continue; + } + /* Try to find a good middle element */ + mid= low + size * (count >> 1); + if (count > 40) /* Must be bigger than 24 */ + { + size_t step = size* (count / 8); + MEDIAN(low, low + step, low+step*2); + MEDIAN(mid - step, mid, mid+step); + MEDIAN(high - 2 * step, high-step, high); + /* Put best median in 'mid' */ + MEDIAN(low+step, mid, high-step); + low_ptr = low; + high_ptr = high; + } + else + { + MEDIAN(low, mid, high); + /* The low and high argument are already in sorted against 'pivot' */ + low_ptr = low + size; + high_ptr = high - size; + } + memcpy(pivot, mid, size); - /* Set up pointers for next iteration. First determine whether - left and right partitions are below the threshold size. If so, - ignore one or both. Otherwise, push the larger partition's - bounds on the stack and continue sorting the smaller one. */ + do + { + while (CMP(low_ptr, pivot) < 0) + low_ptr += size; + while (CMP(pivot, high_ptr) < 0) + high_ptr -= size; - if ((size_t) (right_ptr - lo) <= max_thresh) + if (low_ptr < high_ptr) { - if ((size_t) (hi - left_ptr) <= max_thresh) - POP (lo, hi); /* Ignore both small partitions. */ - else - lo = left_ptr; /* Ignore small left part. */ + SWAP(low_ptr, high_ptr, size, ptr_cmp); + low_ptr += size; + high_ptr -= size; } - else if ((size_t) (hi - left_ptr) <= max_thresh) - hi = right_ptr; /* Ignore small right partition. */ - else if ((right_ptr - lo) > (hi - left_ptr)) - { - PUSH (lo, right_ptr); /* Push larger left part */ - lo = left_ptr; - } - else + else { - PUSH (left_ptr, hi); /* Push larger right part */ - hi = right_ptr; + if (low_ptr == high_ptr) + { + low_ptr += size; + high_ptr -= size; + } + break; } - } while (STACK_NOT_EMPTY); - my_afree(pivot); - } - - /* Once the BASE_PTR array is partially sorted by quicksort the rest - is completely sorted using insertion sort, since this is efficient - for partitions below MAX_THRESH size. BASE_PTR points to the beginning - of the array to sort, and END_PTR points at the very last element in - the array (*not* one beyond it!). */ - - { - char *end_ptr = (char*) base_ptr + size * (total_elems - 1); - char *tmp_ptr = (char*) base_ptr; - char *thresh = min (end_ptr, (char*) base_ptr + max_thresh); - register char *run_ptr; - - /* Find smallest element in first threshold and place it at the - array's beginning. This is the smallest array element, - and the operation speeds up insertion sort's inner loop. */ - - for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) - if (CMP (run_ptr, tmp_ptr) < 0) - tmp_ptr = run_ptr; - - if (tmp_ptr != (char*) base_ptr) - SWAP (tmp_ptr, (char*) base_ptr, size); + } + while (low_ptr <= high_ptr); - /* Insertion sort, running from left-hand-side up to right-hand-side. */ + /* + Prepare for next iteration. + Skip partitions of size 1 as these doesn't have to be sorted + Push the larger partition and sort the smaller one first. + This ensures that the stack is keept small. + */ - for (run_ptr = (char*) base_ptr + size; - (run_ptr += size) <= end_ptr; ) + if ((int) (high_ptr - low) <= 0) { - if (CMP (run_ptr, (tmp_ptr = run_ptr-size)) < 0) + if ((int) (high - low_ptr) <= 0) { - char *trav; - while (CMP (run_ptr, tmp_ptr -= size) < 0) ; - tmp_ptr += size; - - /* Shift down all smaller elements, put found element in 'run_ptr' */ - for (trav = run_ptr + size; --trav >= run_ptr;) - { - char c = *trav; - char *hi, *lo; - - for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) - *hi = *lo; - *hi = c; - } + POP(low, high); /* Nothing more to sort */ } + else + low = low_ptr; /* Ignore small left part. */ + } + else if ((int) (high - low_ptr) <= 0) + high = high_ptr; /* Ignore small right part. */ + else if ((high_ptr - low) > (high - low_ptr)) + { + PUSH(low, high_ptr); /* Push larger left part */ + low = low_ptr; + } + else + { + PUSH(low_ptr, high); /* Push larger right part */ + high = high_ptr; } - } + } while (stack_ptr > stack); + my_afree(pivot); SORT_RETURN; } diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index db482454e69..0c61d2ede3c 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -55,6 +55,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) return((gptr) 0); /* purecov: inspected */ } next->next=mem_root->used; + next->size= Size; mem_root->used=next; return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))); #else @@ -100,7 +101,34 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) #endif } - /* deallocate everything used by alloc_root */ +/* Mark all data in blocks free for reusage */ + +static inline void mark_blocks_free(MEM_ROOT* root) +{ + reg1 USED_MEM *next; + reg2 USED_MEM **last; + + /* iterate through (partially) free blocks, mark them free */ + last= &root->free; + for (next= root->free; next; next= *(last= &next->next)) + next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); + + /* Combine the free and the used list */ + *last= next=root->used; + + /* now go through the used blocks and mark them free */ + for (; next; next= next->next) + next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); + + /* Now everything is set; Indicate that nothing is used anymore */ + root->used= 0; +} + + +/* + Deallocate everything used by alloc_root or just move + used blocks to free list if called with MY_USED_TO_FREE +*/ void free_root(MEM_ROOT *root, myf MyFlags) { @@ -109,18 +137,23 @@ void free_root(MEM_ROOT *root, myf MyFlags) if (!root) DBUG_VOID_RETURN; /* purecov: inspected */ + if (MyFlags & MY_MARK_BLOCKS_FREE) + { + mark_blocks_free(root); + DBUG_VOID_RETURN; + } if (!(MyFlags & MY_KEEP_PREALLOC)) root->pre_alloc=0; - for ( next=root->used; next ;) + for (next=root->used; next ;) { old=next; next= next->next ; if (old != root->pre_alloc) my_free((gptr) old,MYF(0)); } - for (next= root->free ; next ; ) + for (next=root->free ; next ;) { - old=next; next= next->next ; + old=next; next= next->next; if (old != root->pre_alloc) my_free((gptr) old,MYF(0)); } @@ -134,6 +167,31 @@ void free_root(MEM_ROOT *root, myf MyFlags) DBUG_VOID_RETURN; } +/* + Find block that contains an object and set the pre_alloc to it +*/ + +void set_prealloc_root(MEM_ROOT *root, char *ptr) +{ + USED_MEM *next; + for (next=root->used; next ; next=next->next) + { + if ((char*) next <= ptr && (char*) next + next->size > ptr) + { + root->pre_alloc=next; + return; + } + } + for (next=root->free ; next ; next=next->next) + { + if ((char*) next <= ptr && (char*) next + next->size > ptr) + { + root->pre_alloc=next; + return; + } + } +} + char *strdup_root(MEM_ROOT *root,const char *str) { diff --git a/mysys/my_compress.c b/mysys/my_compress.c index d1e32234135..11204562ac8 100644 --- a/mysys/my_compress.c +++ b/mysys/my_compress.c @@ -15,12 +15,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */ +/* Written by Sinisa Milivojevic <sinisa@mysql.com> */ #include <global.h> #ifdef HAVE_COMPRESS #include <my_sys.h> #include <zlib.h> +#include <m_string.h> /* ** This replaces the packet with a compressed packet diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 77d5f311418..dc1e292a893 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -16,7 +16,6 @@ MA 02111-1307, USA */ #include "mysys_priv.h" - #include "mysys_err.h" int my_delete(const char *name, myf MyFlags) diff --git a/mysys/my_dup.c b/mysys/my_dup.c new file mode 100644 index 00000000000..5191a3bed37 --- /dev/null +++ b/mysys/my_dup.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + +#define USES_TYPES +#include "mysys_priv.h" +#include "mysys_err.h" +#include <my_dir.h> +#include <errno.h> +#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__) +#include <share.h> +#endif + + /* Open a file */ + +File my_dup(File file, myf MyFlags) +{ + File fd; + const char *filename; + DBUG_ENTER("my_dup"); + DBUG_PRINT("my",("file: %d MyFlags: %d", MyFlags)); + fd = dup(file); + filename= (((int) file < MY_NFILE) ? + my_file_info[(int) file].name : "Unknown"); + DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP, + EE_FILENOTFOUND, MyFlags)); +} /* my_open */ diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c index d93caadbcdc..a38e1334bca 100644 --- a/mysys/my_fstream.c +++ b/mysys/my_fstream.c @@ -147,7 +147,8 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags) /* Seek to position in file */ /* ARGSUSED */ -my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags) +my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, + myf MyFlags __attribute__((unused))) { DBUG_ENTER("my_fseek"); DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d", @@ -160,7 +161,7 @@ my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags) /* Tell current position of file */ /* ARGSUSED */ -my_off_t my_ftell(FILE *stream, myf MyFlags) +my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused))) { off_t pos; DBUG_ENTER("my_ftell"); diff --git a/mysys/my_lib.c b/mysys/my_lib.c index f9774d8a4aa..d183be58231 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -580,13 +580,15 @@ error: ** Note that MY_STAT is assumed to be same as struct stat ****************************************************************************/ -int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags ) +int my_fstat(int Filedes, MY_STAT *stat_area, + myf MyFlags __attribute__((unused))) { DBUG_ENTER("my_fstat"); DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags)); DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area)); } + MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) { int m_used; diff --git a/mysys/my_seek.c b/mysys/my_seek.c index d8e8cf83b6d..39d376c1eae 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -20,7 +20,7 @@ /* Seek to position in file */ /*ARGSUSED*/ -my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags) +my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags __attribute__((unused))) { reg1 os_off_t newpos; DBUG_ENTER("my_seek"); @@ -40,7 +40,7 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags) /* Tell current position of file */ /* ARGSUSED */ -my_off_t my_tell(File fd, myf MyFlags) +my_off_t my_tell(File fd, myf MyFlags __attribute__((unused))) { os_off_t pos; DBUG_ENTER("my_tell"); diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index f1e90abaa9b..e77815df12a 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -23,6 +23,7 @@ */ #include "mysys_priv.h" +#include "mysys_err.h" #include <m_string.h> File my_create_with_symlink(const char *linkname, const char *filename, @@ -30,11 +31,27 @@ File my_create_with_symlink(const char *linkname, const char *filename, { File file; int tmp_errno; + /* Test if we should create a link */ + int create_link=(linkname && strcmp(linkname,filename)); DBUG_ENTER("my_create_with_symlink"); + + if (!(MyFlags & MY_DELETE_OLD)) + { + if (!access(filename,F_OK)) + { + my_error(EE_CANTCREATEFILE, MYF(0), filename, EEXIST); + DBUG_RETURN(-1); + } + if (create_link && !access(linkname,F_OK)) + { + my_error(EE_CANTCREATEFILE, MYF(0), linkname, EEXIST); + DBUG_RETURN(-1); + } + } + if ((file=my_create(filename, createflags, access_flags, MyFlags)) >= 0) { - /* Test if we should create a link */ - if (linkname && strcmp(linkname,filename)) + if (create_link) { /* Delete old link/file */ if (MyFlags & MY_DELETE_OLD) diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 65b2c51aafd..f9b3e34d702 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -19,9 +19,6 @@ get_ptr_compare(len) returns a pointer to a optimal byte-compare function for a array of stringpointer where all strings have size len. The bytes are compare as unsigned chars. - Because the size is saved in a static variable. - When using threads the program must have called my_init and the thread - my_init_thread() */ #include "mysys_priv.h" diff --git a/mysys/raid.cc b/mysys/raid.cc index 48aa5cdb134..2e17a2c3f58 100644 --- a/mysys/raid.cc +++ b/mysys/raid.cc @@ -420,8 +420,8 @@ IsRaid(File fd) RaidFd:: RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize) :_raid_type(raid_type), _raid_chunks(raid_chunks), - _raid_chunksize(raid_chunksize), _position(0), _fd_vector(0), - _size(RAID_SIZE_UNKNOWN) + _raid_chunksize(raid_chunksize), _position(0), _size(RAID_SIZE_UNKNOWN), + _fd_vector(0) { DBUG_ENTER("RaidFd::RaidFd"); DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %d", diff --git a/mysys/string.c b/mysys/string.c index 96a503c1179..2e0f4d3c9fe 100644 --- a/mysys/string.c +++ b/mysys/string.c @@ -51,7 +51,7 @@ my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str) { - uint length; + uint length=0; DBUG_ENTER("dynstr_set"); if (init_str && (length= (uint) strlen(init_str)+1) > str->max_length) diff --git a/mysys/tree.c b/mysys/tree.c index cd05a17fd72..d3d67b83810 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -62,28 +62,35 @@ static void rb_delete_fixup(TREE *tree,TREE_ELEMENT ***parent); /* The actuall code for handling binary trees */ -void init_tree(TREE *tree, uint default_alloc_size, int size, - qsort_cmp compare, my_bool with_delete, - void (*free_element) (void *)) +#ifndef DBUG_OFF +static int test_rb_tree(TREE_ELEMENT *element); +#endif + +void init_tree(TREE *tree, uint default_alloc_size, uint memory_limit, + int size, qsort_cmp2 compare, my_bool with_delete, + tree_element_free free_element, void *custom_arg) { DBUG_ENTER("init_tree"); DBUG_PRINT("enter",("tree: %lx size: %d",tree,size)); - if (!default_alloc_size) - default_alloc_size= DEFAULT_ALLOC_SIZE; + if (!default_alloc_size) + default_alloc_size= DEFAULT_ALLOC_SIZE; bzero((gptr) &tree->null_element,sizeof(tree->null_element)); tree->root= &tree->null_element; tree->compare=compare; tree->size_of_element=size > 0 ? (uint) size : 0; + tree->memory_limit=memory_limit; tree->free=free_element; + tree->allocated=0; tree->elements_in_tree=0; + tree->custom_arg = custom_arg; tree->null_element.colour=BLACK; tree->null_element.left=tree->null_element.right=0; if (!free_element && size >= 0 && ((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1)))) { tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */ - /* Fix allocation size so that we don't loose any memory */ + /* Fix allocation size so that we don't lose any memory */ default_alloc_size/=(sizeof(TREE_ELEMENT)+size); if (!default_alloc_size) default_alloc_size=1; @@ -102,9 +109,9 @@ void init_tree(TREE *tree, uint default_alloc_size, int size, DBUG_VOID_RETURN; } -void delete_tree(TREE *tree) +static void free_tree(TREE *tree, myf free_flags) { - DBUG_ENTER("delete_tree"); + DBUG_ENTER("free_tree"); DBUG_PRINT("enter",("tree: %lx",tree)); if (tree->root) /* If initialized */ @@ -114,24 +121,43 @@ void delete_tree(TREE *tree) else { if (tree->free) + { + if (tree->memory_limit) + (*tree->free)(NULL, free_init, tree->custom_arg); delete_tree_element(tree,tree->root); - free_root(&tree->mem_root,MYF(0)); + if (tree->memory_limit) + (*tree->free)(NULL, free_end, tree->custom_arg); + } + free_root(&tree->mem_root, free_flags); } } tree->root= &tree->null_element; tree->elements_in_tree=0; + tree->allocated=0; DBUG_VOID_RETURN; } +void delete_tree(TREE* tree) +{ + free_tree(tree, MYF(0)); /* my_free() mem_root if applicable */ +} + +void reset_tree(TREE* tree) +{ + free_tree(tree, MYF(MY_MARK_BLOCKS_FREE)); + /* do not my_free() mem_root if applicable, just mark blocks as free */ +} + + static void delete_tree_element(TREE *tree, TREE_ELEMENT *element) { if (element != &tree->null_element) { delete_tree_element(tree,element->left); - delete_tree_element(tree,element->right); if (tree->free) - (*tree->free)(ELEMENT_KEY(tree,element)); + (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg); + delete_tree_element(tree,element->right); if (tree->with_delete) my_free((char*) element,MYF(0)); } @@ -152,7 +178,8 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size) for (;;) { if (element == &tree->null_element || - (cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0) + (cmp=(*tree->compare)(tree->custom_arg, + ELEMENT_KEY(tree,element),key)) == 0) break; if (cmp < 0) { @@ -165,13 +192,22 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size) } if (element == &tree->null_element) { + uint alloc_size=sizeof(TREE_ELEMENT)+key_size+tree->size_of_element; + tree->allocated+=alloc_size; + + if (tree->memory_limit && tree->elements_in_tree + && tree->allocated > tree->memory_limit) + { + reset_tree(tree); + return tree_insert(tree, key, key_size); + } + key_size+=tree->size_of_element; if (tree->with_delete) - element=(TREE_ELEMENT *) my_malloc(sizeof(TREE_ELEMENT)+key_size, - MYF(MY_WME)); + element=(TREE_ELEMENT *) my_malloc(alloc_size, MYF(MY_WME)); else element=(TREE_ELEMENT *) - alloc_root(&tree->mem_root,sizeof(TREE_ELEMENT)+key_size); + alloc_root(&tree->mem_root,alloc_size); if (!element) return(NULL); **parent=element; @@ -195,6 +231,7 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size) } else element->count++; + DBUG_EXECUTE("check_tree", test_rb_tree(tree->root);); return element; } @@ -212,7 +249,8 @@ int tree_delete(TREE *tree, void *key) { if (element == &tree->null_element) return 1; /* Was not in tree */ - if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0) + if ((cmp=(*tree->compare)(tree->custom_arg, + ELEMENT_KEY(tree,element),key)) == 0) break; if (cmp < 0) { @@ -252,7 +290,7 @@ int tree_delete(TREE *tree, void *key) if (remove_colour == BLACK) rb_delete_fixup(tree,parent); if (tree->free) - (*tree->free)(ELEMENT_KEY(tree,element)); + (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg); my_free((gptr) element,MYF(0)); tree->elements_in_tree--; return 0; @@ -268,7 +306,8 @@ void *tree_search(TREE *tree, void *key) { if (element == &tree->null_element) return (void*) 0; - if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0) + if ((cmp=(*tree->compare)(tree->custom_arg, + ELEMENT_KEY(tree,element),key)) == 0) return ELEMENT_KEY(tree,element); if (cmp < 0) element=element->right; @@ -484,8 +523,7 @@ static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent) x->colour=BLACK; } - -#ifdef TESTING_TREES +#ifndef DBUG_OFF /* Test that the proporties for a red-black tree holds */ @@ -511,5 +549,4 @@ static int test_rb_tree(TREE_ELEMENT *element) } return -1; } - #endif diff --git a/pstack/Makefile.am b/pstack/Makefile.am new file mode 100644 index 00000000000..1c0978379d0 --- /dev/null +++ b/pstack/Makefile.am @@ -0,0 +1,25 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# +# 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 + +INCLUDES = -I$(srcdir)/../include -I../include +pkglib_LIBRARIES = libpstack.a +noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \ + linuxthreads.h pstack.h pstacktrace.h +libpstack_a_SOURCES = bucomm.c filemode.c linuxthreads.c rddbg.c \ + debug.c ieee.c pstack.c stabs.c + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/pstack/aout/aout64.h b/pstack/aout/aout64.h new file mode 100644 index 00000000000..76f1140b682 --- /dev/null +++ b/pstack/aout/aout64.h @@ -0,0 +1,475 @@ +/* `a.out' object-file definitions, including extensions to 64-bit fields */ + +#ifndef __A_OUT_64_H__ +#define __A_OUT_64_H__ + +/* This is the layout on disk of the 32-bit or 64-bit exec header. */ + +#ifndef external_exec +struct external_exec +{ + bfd_byte e_info[4]; /* magic number and stuff */ + bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */ + bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */ + bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */ + bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */ + bfd_byte e_entry[BYTES_IN_WORD]; /* start address */ + bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */ + bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */ +}; + +#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) + +/* Magic numbers for a.out files */ + +#if ARCH_SIZE==64 +#define OMAGIC 0x1001 /* Code indicating object file */ +#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */ +#define NMAGIC 0x1003 /* Code indicating pure executable. */ + +/* There is no 64-bit QMAGIC as far as I know. */ + +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#else +#define OMAGIC 0407 /* ...object file or impure executable. */ +#define NMAGIC 0410 /* Code indicating pure executable. */ +#define ZMAGIC 0413 /* Code indicating demand-paged executable. */ +#define BMAGIC 0415 /* Used by a b.out object. */ + +/* This indicates a demand-paged executable with the header in the text. + It is used by 386BSD (and variants) and Linux, at least. */ +#ifndef QMAGIC +#define QMAGIC 0314 +#endif +# ifndef N_BADMAG +# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +# endif /* N_BADMAG */ +#endif + +#endif + +#ifdef QMAGIC +#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC) +#else +#define N_IS_QMAGIC(x) (0) +#endif + +/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is + the finest granularity at which you can page something, thus it + controls the padding (if any) before the text segment of a ZMAGIC + file. N_SEGSIZE is the resolution at which things can be marked as + read-only versus read/write, so it controls the padding between the + text segment and the data segment (in memory; on disk the padding + between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same + for most machines, but different for sun3. */ + +/* By default, segment size is constant. But some machines override this + to be a function of the a.out header (e.g. machine type). */ + +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + +/* Virtual memory address of the text section. + This is getting very complicated. A good reason to discard a.out format + for something that specifies these fields explicitly. But til then... + + * OMAGIC and NMAGIC files: + (object files: text for "relocatable addr 0" right after the header) + start at 0, offset is EXEC_BYTES_SIZE, size as stated. + * The text address, offset, and size of ZMAGIC files depend + on the entry point of the file: + * entry point below TEXT_START_ADDR: + (hack for SunOS shared libraries) + start at 0, offset is 0, size as stated. + * If N_HEADER_IN_TEXT(x) is true (which defaults to being the + case when the entry point is EXEC_BYTES_SIZE or further into a page): + no padding is needed; text can start after exec header. Sun + considers the text segment of such files to include the exec header; + for BFD's purposes, we don't, which makes more work for us. + start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE, + size as stated minus EXEC_BYTES_SIZE. + * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when + the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page + aligned)): (padding is needed so that text can start at a page boundary) + start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated. + + Specific configurations may want to hardwire N_HEADER_IN_TEXT, + for efficiency or to allow people to play games with the entry point. + In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos, + and as 0 for most other hosts (Sony News, Vax Ultrix, etc). + (Do this in the appropriate bfd target file.) + (The default is a heuristic that will break if people try changing + the entry point, perhaps with the ld -e flag.) + + * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true, + and for which the starting address is TARGET_PAGE_SIZE (or should this be + SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC). + */ + +/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header + in the text. */ +#ifndef N_HEADER_IN_TEXT +#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE) +#endif + +/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC + files. */ +#ifndef N_SHARED_LIB +#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR) +#endif + +/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on + the assumption that we are dealing with a .o file, not an + executable. This is necessary for OMAGIC (but means we don't work + right on the output from ld -N); more questionable for NMAGIC. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(x) \ + (/* The address of a QMAGIC file is always one page in, */ \ + /* with the header in the text. */ \ + N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \ + N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\ + TEXT_START_ADDR /* a page of padding */\ + ) +#endif + +/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding + to make the text segment start at a certain boundary. For most + systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the + time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is + not what TARGET_PAGE_SIZE needs to be for QMAGIC. */ + +#ifndef ZMAGIC_DISK_BLOCK_SIZE +#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE +#endif + +#define N_DISK_BLOCK_SIZE(x) \ + (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE) + +/* Offset in an a.out of the start of the text section. */ +#ifndef N_TXTOFF +#define N_TXTOFF(x) \ + (/* For {O,N,Q}MAGIC, no padding. */ \ + N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \ + N_SHARED_LIB(x) ? 0 : \ + N_HEADER_IN_TEXT(x) ? \ + EXEC_BYTES_SIZE : /* no padding */\ + ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\ + ) +#endif +/* Size of the text section. It's always as stated, except that we + offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF + for ZMAGIC files that nominally include the exec header + as part of the first page of text. (BFD doesn't consider the + exec header to be part of the text segment.) */ +#ifndef N_TXTSIZE +#define N_TXTSIZE(x) \ + (/* For QMAGIC, we don't consider the header part of the text section. */\ + N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \ + (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \ + N_HEADER_IN_TEXT(x) ? \ + (x).a_text - EXEC_BYTES_SIZE: /* no padding */\ + (x).a_text /* a page of padding */\ + ) +#endif +/* The address of the data segment in virtual memory. + It is the text segment address, plus text segment size, rounded + up to a N_SEGSIZE boundary for pure or pageable files. */ +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \ + : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1)))) +#endif +/* The address of the BSS segment -- immediately after the data segment. */ + +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) + +/* Offsets of the various portions of the file after the text segment. */ + +/* For {Q,Z}MAGIC, there is padding to make the data segment start on + a page boundary. Most of the time the a_text field (and thus + N_TXTSIZE) already contains this padding. It is possible that for + BSDI and/or 386BSD it sometimes doesn't contain the padding, and + perhaps we should be adding it here. But this seems kind of + questionable and probably should be BSDI/386BSD-specific if we do + do it. + + For NMAGIC (at least for hp300 BSD, probably others), there is + padding in memory only, not on disk, so we must *not* ever pad here + for NMAGIC. */ + +#ifndef N_DATOFF +#define N_DATOFF(x) \ + (N_TXTOFF(x) + N_TXTSIZE(x)) +#endif + +#ifndef N_TRELOFF +#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) +#endif +#ifndef N_DRELOFF +#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) +#endif +#ifndef N_SYMOFF +#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) +#endif +#ifndef N_STROFF +#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) +#endif + +/* Symbols */ +#ifndef external_nlist +struct external_nlist { + bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */ + bfd_byte e_type[1]; /* type of symbol */ + bfd_byte e_other[1]; /* misc info (usually empty) */ + bfd_byte e_desc[2]; /* description field */ + bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */ +}; +#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) +#endif + +struct internal_nlist { + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + bfd_vma n_value; /* value of symbol */ +}; + +/* The n_type field is the symbol type, containing: */ + +#define N_UNDF 0 /* Undefined symbol */ +#define N_ABS 2 /* Absolute symbol -- defined at particular addr */ +#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ +#define N_FN 0x1f /* File name of .o file */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ +#define N_TYPE 0x1e +#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */ + +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Weak symbols. These are a GNU extension to the a.out format. The + semantics are those of ELF weak symbols. Weak symbols are always + externally visible. The N_WEAK? values are squeezed into the + available slots. The value of a N_WEAKU symbol is 0. The values + of the other types are the definitions. */ +#define N_WEAKU 0x0d /* Weak undefined symbol. */ +#define N_WEAKA 0x0e /* Weak absolute symbol. */ +#define N_WEAKT 0x0f /* Weak text symbol. */ +#define N_WEAKD 0x10 /* Weak data symbol. */ +#define N_WEAKB 0x11 /* Weak bss symbol. */ + +/* Relocations + + There are two types of relocation flavours for a.out systems, + standard and extended. The standard form is used on systems where the + instruction has room for all the bits of an offset to the operand, whilst + the extended form is used when an address operand has to be split over n + instructions. Eg, on the 68k, each move instruction can reference + the target with a displacement of 16 or 32 bits. On the sparc, move + instructions use an offset of 14 bits, so the offset is stored in + the reloc field, and the data in the section is ignored. +*/ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct reloc_std_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ +}; + +#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80) +#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01) + +#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60) +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 +#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06) +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10) +#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08) + +#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08) +#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10) + +#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04) +#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20) + +#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02) +#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40) + +#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */ + +struct reloc_std_internal +{ + bfd_vma r_address; /* Address (within segment) to be relocated. */ + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in files the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative */ + unsigned int r_jmptable:1; /* pc-relative to jump table */ + unsigned int r_relative:1; /* "relative relocation" */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero */ +}; + + +/* EXTENDED RELOCS */ + +struct reloc_ext_external { + bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ + bfd_byte r_index[3]; /* symbol table index of symbol */ + bfd_byte r_type[1]; /* relocation type */ + bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */ +}; + +#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80) +#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01) + +#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F) +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8) +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 + +/* Bytes per relocation entry */ +#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) + +enum reloc_type +{ + /* simple relocations */ + RELOC_8, /* data[0:7] = addend + sv */ + RELOC_16, /* data[0:15] = addend + sv */ + RELOC_32, /* data[0:31] = addend + sv */ + /* pc-rel displacement */ + RELOC_DISP8, /* data[0:7] = addend - pc + sv */ + RELOC_DISP16, /* data[0:15] = addend - pc + sv */ + RELOC_DISP32, /* data[0:31] = addend - pc + sv */ + /* Special */ + RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ + RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ + RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ + RELOC_22, /* data[0:21] = (addend + sv) */ + RELOC_13, /* data[0:12] = (addend + sv) */ + RELOC_LO10, /* data[0:9] = (addend + sv) */ + RELOC_SFA_BASE, + RELOC_SFA_OFF13, + /* P.I.C. (base-relative) */ + RELOC_BASE10, /* Not sure - maybe we can do this the */ + RELOC_BASE13, /* right way now */ + RELOC_BASE22, + /* for some sort of pc-rel P.I.C. (?) */ + RELOC_PC10, + RELOC_PC22, + /* P.I.C. jump table */ + RELOC_JMP_TBL, + /* reputedly for shared libraries somehow */ + RELOC_SEGOFF16, + RELOC_GLOB_DAT, + RELOC_JMP_SLOT, + RELOC_RELATIVE, + + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ + RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ + + /* 29K relocation types */ + RELOC_JUMPTARG, + RELOC_CONST, + RELOC_CONSTH, + + /* All the new ones I can think of, for sparc v9 */ + + RELOC_64, /* data[0:63] = addend + sv */ + RELOC_DISP64, /* data[0:63] = addend - pc + sv */ + RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */ + RELOC_DISP21, /* data[0:20] = addend - pc + sv */ + RELOC_DISP14, /* data[0:13] = addend - pc + sv */ + /* Q . + What are the other ones, + Since this is a clean slate, can we throw away the ones we dont + understand ? Should we sort the values ? What about using a + microcode format like the 68k ? + */ + NO_RELOC + }; + + +struct reloc_internal { + bfd_vma r_address; /* offset of of data to relocate */ + long r_index; /* symbol table index of symbol */ + enum reloc_type r_type; /* relocation type */ + bfd_vma r_addend; /* datum addend */ +}; + +/* Q. + Should the length of the string table be 4 bytes or 8 bytes ? + + Q. + What about archive indexes ? + + */ + +#endif /* __A_OUT_64_H__ */ diff --git a/pstack/aout/stab.def b/pstack/aout/stab.def new file mode 100644 index 00000000000..3c6b456d3a9 --- /dev/null +++ b/pstack/aout/stab.def @@ -0,0 +1,264 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + +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. */ + +/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files + overlaps the N_UNDF used for ordinary symbols. In ELF files, the + debug information is in a different file section, so there is no conflict. + This symbol's n_value gives the size of the string section associated + with this file. The symbol's n_strx (relative to the just-updated + string section start address) gives the name of the source file, + e.g. "foo.c", without any path information. The symbol's n_desc gives + the count of upcoming symbols associated with this file (not including + this one). */ +/* __define_stab (N_UNDF, 0x00, "UNDF") */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Solaris2: Read-only data symbols. */ +__define_stab (N_ROSYM, 0x2c, "ROSYM") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris 2. Like N_SO, but for the object file. Two in + a row provide the build directory and the relative path of the .o from it. + Solaris2 uses this to avoid putting the stabs info into the linked + executable; this stab goes into the ".stab.index" section, and the debugger + reads the real stabs directly from the .o files instead. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris 2. Options for the debugger, related to the + source language for this module. E.g. whether to use ANSI + integral promotions or traditional integral promotions. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. On Solaris2, the line number is + relative to the start of the current function. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab_duplicate (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* New in Solaris2. Function start/body/end line numbers. */ +__define_stab(N_FLINE, 0x4C, "FLINE") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab_duplicate (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Solaris2: Last stab emitted for module. */ +__define_stab (N_ENDM, 0x62, "ENDM") + +/* Name of main source file. + Value is starting text address of the compilation. + If multiple N_SO's appear, the first to contain a trailing / is the + compilation directory. The first to not contain a trailing / is the + source file name, relative to the compilation directory. Others (perhaps + resulting from cfront) are ignored. + On Solaris2, value is undefined, but desc is a source-language code. */ + +__define_stab (N_SO, 0x64, "SO") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* Member of a common block; value is offset within the common block. + This should occur within a BCOMM/ECOMM pair. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* Solaris2: Pascal "with" statement: type,,0,0,offset */ +__define_stab (N_WITH, 0xea, "WITH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | + | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | + + | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | + | 11 WEAKB | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 ENDM | 64 SO | 66 | + | 68 | 6A | 6C | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA WITH | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/pstack/aout/stab_gnu.h b/pstack/aout/stab_gnu.h new file mode 100644 index 00000000000..7d18e14a263 --- /dev/null +++ b/pstack/aout/stab_gnu.h @@ -0,0 +1,37 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, +#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "aout/stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab + +/* Definitions of "desc" field for N_SO stabs in Solaris2. */ + +#define N_SO_AS 1 +#define N_SO_C 2 +#define N_SO_ANSI_C 3 +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 +#define N_SO_PASCAL 6 + +/* Solaris2: Floating point type values in basic types. */ + +#define NF_NONE 0 +#define NF_SINGLE 1 /* IEEE 32-bit */ +#define NF_DOUBLE 2 /* IEEE 64-bit */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double (whatever that is) */ + +#endif /* __GNU_STAB_ */ diff --git a/pstack/bucomm.c b/pstack/bucomm.c new file mode 100644 index 00000000000..d3231e71747 --- /dev/null +++ b/pstack/bucomm.c @@ -0,0 +1,238 @@ +/* bucomm.c -- Bin Utils COMmon code. + Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + 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. */ + +/* We might put this in a library someday so it could be dynamically + loaded, but for now it's not necessary. */ + +#include <bfd.h> +#include <libiberty.h> +#include "bucomm.h" + +#include <sys/stat.h> +#include <time.h> /* ctime, maybe time_t */ + +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +/* Error reporting */ + +char *program_name; + +void +bfd_nonfatal (string) + CONST char *string; +{ + CONST char *errmsg = bfd_errmsg (bfd_get_error ()); + + if (string) + fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); + else + fprintf (stderr, "%s: %s\n", program_name, errmsg); +} + +void +bfd_fatal (string) + CONST char *string; +{ + bfd_nonfatal (string); + xexit (1); +} + +#ifdef ANSI_PROTOTYPES +void +fatal (const char *format, ...) +{ + va_list args; + + fprintf (stderr, "%s: ", program_name); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + putc ('\n', stderr); + xexit (1); +} +#else +void +fatal (va_alist) + va_dcl +{ + char *Format; + va_list args; + + fprintf (stderr, "%s: ", program_name); + va_start (args); + Format = va_arg (args, char *); + vfprintf (stderr, Format, args); + va_end (args); + putc ('\n', stderr); + xexit (1); +} +#endif + +/* Set the default BFD target based on the configured target. Doing + this permits the binutils to be configured for a particular target, + and linked against a shared BFD library which was configured for a + different target. */ + +#define TARGET "elf32-i386" /* FIXME: hard-coded! */ +void +set_default_bfd_target () +{ + /* The macro TARGET is defined by Makefile. */ + const char *target = TARGET; + + if (! bfd_set_default_target (target)) + { + char *errmsg; + + errmsg = (char *) xmalloc (100 + strlen (target)); + sprintf (errmsg, "can't set BFD default target to `%s'", target); + bfd_fatal (errmsg); + } +} + +/* After a false return from bfd_check_format_matches with + bfd_get_error () == bfd_error_file_ambiguously_recognized, print + the possible matching targets. */ + +void +list_matching_formats (p) + char **p; +{ + fprintf(stderr, "%s: Matching formats:", program_name); + while (*p) + fprintf(stderr, " %s", *p++); + fprintf(stderr, "\n"); +} + +/* List the supported targets. */ + +void +list_supported_targets (name, f) + const char *name; + FILE *f; +{ + extern bfd_target *bfd_target_vector[]; + int t; + + if (name == NULL) + fprintf (f, "Supported targets:"); + else + fprintf (f, "%s: supported targets:", name); + for (t = 0; bfd_target_vector[t] != NULL; t++) + fprintf (f, " %s", bfd_target_vector[t]->name); + fprintf (f, "\n"); +} + +/* Display the archive header for an element as if it were an ls -l listing: + + Mode User\tGroup\tSize\tDate Name */ + +void +print_arelt_descr (file, abfd, verbose) + FILE *file; + bfd *abfd; + boolean verbose; +{ + struct stat buf; + + if (verbose) + { + if (bfd_stat_arch_elt (abfd, &buf) == 0) + { + char modebuf[11]; + char timebuf[40]; + time_t when = buf.st_mtime; + CONST char *ctime_result = (CONST char *) ctime (&when); + + /* POSIX format: skip weekday and seconds from ctime output. */ + sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); + + mode_string (buf.st_mode, modebuf); + modebuf[10] = '\0'; + /* POSIX 1003.2/D11 says to skip first character (entry type). */ + fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, + (long) buf.st_uid, (long) buf.st_gid, + (long) buf.st_size, timebuf); + } + } + + fprintf (file, "%s\n", bfd_get_filename (abfd)); +} + +/* Return the name of a temporary file in the same directory as FILENAME. */ + +char * +make_tempname (filename) + char *filename; +{ + static char template[] = "stXXXXXX"; + char *tmpname; + char *slash = strrchr (filename, '/'); + +#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32) + if (slash == NULL) + slash = strrchr (filename, '\\'); +#endif + + if (slash != (char *) NULL) + { + char c; + + c = *slash; + *slash = 0; + tmpname = xmalloc (strlen (filename) + sizeof (template) + 1); + strcpy (tmpname, filename); + strcat (tmpname, "/"); + strcat (tmpname, template); + mkstemp (tmpname); + *slash = c; + } + else + { + tmpname = xmalloc (sizeof (template)); + strcpy (tmpname, template); + mkstemp (tmpname); + } + return tmpname; +} + +/* Parse a string into a VMA, with a fatal error if it can't be + parsed. */ + +bfd_vma +parse_vma (s, arg) + const char *s; + const char *arg; +{ + bfd_vma ret; + const char *end; + + ret = bfd_scan_vma (s, &end, 0); + if (*end != '\0') + { + fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s); + exit (1); + } + return ret; +} diff --git a/pstack/bucomm.h b/pstack/bucomm.h new file mode 100644 index 00000000000..7712a70f5a2 --- /dev/null +++ b/pstack/bucomm.h @@ -0,0 +1,85 @@ +/* bucomm.h -- binutils common include file. + Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +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 _BUCOMM_H +#define _BUCOMM_H + +#include "ansidecl.h" +#include <stdio.h> +#include <sys/types.h> + +#include <errno.h> +#include <unistd.h> + +#include <string.h> + +#include <stdlib.h> + +#include <fcntl.h> + +#ifdef __GNUC__ +# undef alloca +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if !defined (__STDC__) && !defined (__hpux) +char *alloca (); +# else +void *alloca (); +# endif /* __STDC__, __hpux */ +# endif /* alloca */ +# endif /* HAVE_ALLOCA_H */ +#endif + +/* bucomm.c */ +void bfd_nonfatal PARAMS ((CONST char *)); + +void bfd_fatal PARAMS ((CONST char *)); + +void fatal PARAMS ((CONST char *, ...)); + +void set_default_bfd_target PARAMS ((void)); + +void list_matching_formats PARAMS ((char **p)); + +void list_supported_targets PARAMS ((const char *, FILE *)); + +void print_arelt_descr PARAMS ((FILE *file, bfd *abfd, boolean verbose)); + +char *make_tempname PARAMS ((char *)); + +bfd_vma parse_vma PARAMS ((const char *, const char *)); + +extern char *program_name; + +/* filemode.c */ +void mode_string PARAMS ((unsigned long mode, char *buf)); + +/* version.c */ +extern void print_version PARAMS ((const char *)); + +/* libiberty */ +PTR xmalloc PARAMS ((size_t)); + +PTR xrealloc PARAMS ((PTR, size_t)); + +#endif /* _BUCOMM_H */ diff --git a/pstack/budbg.h b/pstack/budbg.h new file mode 100644 index 00000000000..d8ee8895e76 --- /dev/null +++ b/pstack/budbg.h @@ -0,0 +1,58 @@ +/* budbg.c -- Interfaces to the generic debugging information routines. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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 BUDBG_H +#define BUDBG_H + +#include <stdio.h> + +/* Routine used to read generic debugging information. */ + +extern PTR read_debugging_info PARAMS ((bfd *, asymbol **, long)); + +/* Routine used to print generic debugging information. */ + +extern boolean print_debugging_info PARAMS ((FILE *, PTR)); + +/* Routines used to read and write stabs information. */ + +extern PTR start_stab PARAMS ((PTR, bfd *, boolean, asymbol **, long)); + +extern boolean finish_stab PARAMS ((PTR, PTR)); + +extern boolean parse_stab PARAMS ((PTR, PTR, int, int, bfd_vma, const char *)); + +extern boolean write_stabs_in_sections_debugging_info + PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **, + bfd_size_type *)); + +/* Routines used to read and write IEEE debugging information. */ + +extern boolean parse_ieee + PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type)); + +extern boolean write_ieee_debugging_info PARAMS ((bfd *, PTR)); + +/* Routine used to read COFF debugging information. */ + +extern boolean parse_coff PARAMS ((bfd *, asymbol **, long, PTR)); + +#endif diff --git a/pstack/debug.c b/pstack/debug.c new file mode 100644 index 00000000000..ee62bb17062 --- /dev/null +++ b/pstack/debug.c @@ -0,0 +1,3509 @@ +/* debug.c -- Handle generic debugging information. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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. */ + +/* This file implements a generic debugging format. We may eventually + have readers which convert different formats into this generic + format, and writers which write it out. The initial impetus for + this was writing a convertor from stabs to HP IEEE-695 debugging + format. */ + +#include <stdio.h> +#include <assert.h> + +#include <bfd.h> +#include "bucomm.h" +#include <libiberty.h> +#include "debug.h" + +/* Global information we keep for debugging. A pointer to this + structure is the debugging handle passed to all the routines. */ + +struct debug_handle +{ + /* A linked list of compilation units. */ + struct debug_unit *units; + /* The current compilation unit. */ + struct debug_unit *current_unit; + /* The current source file. */ + struct debug_file *current_file; + /* The current function. */ + struct debug_function *current_function; + /* The current block. */ + struct debug_block *current_block; + /* The current line number information for the current unit. */ + struct debug_lineno *current_lineno; + /* Mark. This is used by debug_write. */ + unsigned int mark; + /* A struct/class ID used by debug_write. */ + unsigned int class_id; + /* The base for class_id for this call to debug_write. */ + unsigned int base_id; + /* The current line number in debug_write. */ + struct debug_lineno *current_write_lineno; + unsigned int current_write_lineno_index; + /* A list of classes which have assigned ID's during debug_write. + This is linked through the next_id field of debug_class_type. */ + struct debug_class_id *id_list; + /* A list used to avoid recursion during debug_type_samep. */ + struct debug_type_compare_list *compare_list; +}; + +/* Information we keep for a single compilation unit. */ + +struct debug_unit +{ + /* The next compilation unit. */ + struct debug_unit *next; + /* A list of files included in this compilation unit. The first + file is always the main one, and that is where the main file name + is stored. */ + struct debug_file *files; + /* Line number information for this compilation unit. This is not + stored by function, because assembler code may have line number + information without function information. */ + struct debug_lineno *linenos; +}; + +/* Information kept for a single source file. */ + +struct debug_file +{ + /* The next source file in this compilation unit. */ + struct debug_file *next; + /* The name of the source file. */ + const char *filename; + /* Global functions, variables, types, etc. */ + struct debug_namespace *globals; +}; + +/* A type. */ + +struct debug_type +{ + /* Kind of type. */ + enum debug_type_kind kind; + /* Size of type (0 if not known). */ + unsigned int size; + /* Type which is a pointer to this type. */ + debug_type pointer; + /* Tagged union with additional information about the type. */ + union + { + /* DEBUG_KIND_INDIRECT. */ + struct debug_indirect_type *kindirect; + /* DEBUG_KIND_INT. */ + /* Whether the integer is unsigned. */ + boolean kint; + /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS, + DEBUG_KIND_UNION_CLASS. */ + struct debug_class_type *kclass; + /* DEBUG_KIND_ENUM. */ + struct debug_enum_type *kenum; + /* DEBUG_KIND_POINTER. */ + struct debug_type *kpointer; + /* DEBUG_KIND_FUNCTION. */ + struct debug_function_type *kfunction; + /* DEBUG_KIND_REFERENCE. */ + struct debug_type *kreference; + /* DEBUG_KIND_RANGE. */ + struct debug_range_type *krange; + /* DEBUG_KIND_ARRAY. */ + struct debug_array_type *karray; + /* DEBUG_KIND_SET. */ + struct debug_set_type *kset; + /* DEBUG_KIND_OFFSET. */ + struct debug_offset_type *koffset; + /* DEBUG_KIND_METHOD. */ + struct debug_method_type *kmethod; + /* DEBUG_KIND_CONST. */ + struct debug_type *kconst; + /* DEBUG_KIND_VOLATILE. */ + struct debug_type *kvolatile; + /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */ + struct debug_named_type *knamed; + } u; +}; + +/* Information kept for an indirect type. */ + +struct debug_indirect_type +{ + /* Slot where the final type will appear. */ + debug_type *slot; + /* Tag. */ + const char *tag; +}; + +/* Information kept for a struct, union, or class. */ + +struct debug_class_type +{ + /* NULL terminated array of fields. */ + debug_field *fields; + /* A mark field which indicates whether the struct has already been + printed. */ + unsigned int mark; + /* This is used to uniquely identify unnamed structs when printing. */ + unsigned int id; + /* The remaining fields are only used for DEBUG_KIND_CLASS and + DEBUG_KIND_UNION_CLASS. */ + /* NULL terminated array of base classes. */ + debug_baseclass *baseclasses; + /* NULL terminated array of methods. */ + debug_method *methods; + /* The type of the class providing the virtual function table for + this class. This may point to the type itself. */ + debug_type vptrbase; +}; + +/* Information kept for an enum. */ + +struct debug_enum_type +{ + /* NULL terminated array of names. */ + const char **names; + /* Array of corresponding values. */ + bfd_signed_vma *values; +}; + +/* Information kept for a function. FIXME: We should be able to + record the parameter types. */ + +struct debug_function_type +{ + /* Return type. */ + debug_type return_type; + /* NULL terminated array of argument types. */ + debug_type *arg_types; + /* Whether the function takes a variable number of arguments. */ + boolean varargs; +}; + +/* Information kept for a range. */ + +struct debug_range_type +{ + /* Range base type. */ + debug_type type; + /* Lower bound. */ + bfd_signed_vma lower; + /* Upper bound. */ + bfd_signed_vma upper; +}; + +/* Information kept for an array. */ + +struct debug_array_type +{ + /* Element type. */ + debug_type element_type; + /* Range type. */ + debug_type range_type; + /* Lower bound. */ + bfd_signed_vma lower; + /* Upper bound. */ + bfd_signed_vma upper; + /* Whether this array is really a string. */ + boolean stringp; +}; + +/* Information kept for a set. */ + +struct debug_set_type +{ + /* Base type. */ + debug_type type; + /* Whether this set is really a bitstring. */ + boolean bitstringp; +}; + +/* Information kept for an offset type (a based pointer). */ + +struct debug_offset_type +{ + /* The type the pointer is an offset from. */ + debug_type base_type; + /* The type the pointer points to. */ + debug_type target_type; +}; + +/* Information kept for a method type. */ + +struct debug_method_type +{ + /* The return type. */ + debug_type return_type; + /* The object type which this method is for. */ + debug_type domain_type; + /* A NULL terminated array of argument types. */ + debug_type *arg_types; + /* Whether the method takes a variable number of arguments. */ + boolean varargs; +}; + +/* Information kept for a named type. */ + +struct debug_named_type +{ + /* Name. */ + struct debug_name *name; + /* Real type. */ + debug_type type; +}; + +/* A field in a struct or union. */ + +struct debug_field +{ + /* Name of the field. */ + const char *name; + /* Type of the field. */ + struct debug_type *type; + /* Visibility of the field. */ + enum debug_visibility visibility; + /* Whether this is a static member. */ + boolean static_member; + union + { + /* If static_member is false. */ + struct + { + /* Bit position of the field in the struct. */ + unsigned int bitpos; + /* Size of the field in bits. */ + unsigned int bitsize; + } f; + /* If static_member is true. */ + struct + { + const char *physname; + } s; + } u; +}; + +/* A base class for an object. */ + +struct debug_baseclass +{ + /* Type of the base class. */ + struct debug_type *type; + /* Bit position of the base class in the object. */ + unsigned int bitpos; + /* Whether the base class is virtual. */ + boolean virtual; + /* Visibility of the base class. */ + enum debug_visibility visibility; +}; + +/* A method of an object. */ + +struct debug_method +{ + /* The name of the method. */ + const char *name; + /* A NULL terminated array of different types of variants. */ + struct debug_method_variant **variants; +}; + +/* The variants of a method function of an object. These indicate + which method to run. */ + +struct debug_method_variant +{ + /* The physical name of the function. */ + const char *physname; + /* The type of the function. */ + struct debug_type *type; + /* The visibility of the function. */ + enum debug_visibility visibility; + /* Whether the function is const. */ + boolean constp; + /* Whether the function is volatile. */ + boolean volatilep; + /* The offset to the function in the virtual function table. */ + bfd_vma voffset; + /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */ +#define VOFFSET_STATIC_METHOD ((bfd_vma) -1) + /* Context of a virtual method function. */ + struct debug_type *context; +}; + +/* A variable. This is the information we keep for a variable object. + This has no name; a name is associated with a variable in a + debug_name structure. */ + +struct debug_variable +{ + /* Kind of variable. */ + enum debug_var_kind kind; + /* Type. */ + debug_type type; + /* Value. The interpretation of the value depends upon kind. */ + bfd_vma val; +}; + +/* A function. This has no name; a name is associated with a function + in a debug_name structure. */ + +struct debug_function +{ + /* Return type. */ + debug_type return_type; + /* Parameter information. */ + struct debug_parameter *parameters; + /* Block information. The first structure on the list is the main + block of the function, and describes function local variables. */ + struct debug_block *blocks; +}; + +/* A function parameter. */ + +struct debug_parameter +{ + /* Next parameter. */ + struct debug_parameter *next; + /* Name. */ + const char *name; + /* Type. */ + debug_type type; + /* Kind. */ + enum debug_parm_kind kind; + /* Value (meaning depends upon kind). */ + bfd_vma val; +}; + +/* A typed constant. */ + +struct debug_typed_constant +{ + /* Type. */ + debug_type type; + /* Value. FIXME: We may eventually need to support non-integral + values. */ + bfd_vma val; +}; + +/* Information about a block within a function. */ + +struct debug_block +{ + /* Next block with the same parent. */ + struct debug_block *next; + /* Parent block. */ + struct debug_block *parent; + /* List of child blocks. */ + struct debug_block *children; + /* Start address of the block. */ + bfd_vma start; + /* End address of the block. */ + bfd_vma end; + /* Local variables. */ + struct debug_namespace *locals; +}; + +/* Line number information we keep for a compilation unit. FIXME: + This structure is easy to create, but can be very space + inefficient. */ + +struct debug_lineno +{ + /* More line number information for this block. */ + struct debug_lineno *next; + /* Source file. */ + struct debug_file *file; + /* Line numbers, terminated by a -1 or the end of the array. */ +#define DEBUG_LINENO_COUNT 10 + unsigned long linenos[DEBUG_LINENO_COUNT]; + /* Addresses for the line numbers. */ + bfd_vma addrs[DEBUG_LINENO_COUNT]; +}; + +/* A namespace. This is a mapping from names to objects. FIXME: This + should be implemented as a hash table. */ + +struct debug_namespace +{ + /* List of items in this namespace. */ + struct debug_name *list; + /* Pointer to where the next item in this namespace should go. */ + struct debug_name **tail; +}; + +/* Kinds of objects that appear in a namespace. */ + +enum debug_object_kind +{ + /* A type. */ + DEBUG_OBJECT_TYPE, + /* A tagged type (really a different sort of namespace). */ + DEBUG_OBJECT_TAG, + /* A variable. */ + DEBUG_OBJECT_VARIABLE, + /* A function. */ + DEBUG_OBJECT_FUNCTION, + /* An integer constant. */ + DEBUG_OBJECT_INT_CONSTANT, + /* A floating point constant. */ + DEBUG_OBJECT_FLOAT_CONSTANT, + /* A typed constant. */ + DEBUG_OBJECT_TYPED_CONSTANT +}; + +/* Linkage of an object that appears in a namespace. */ + +enum debug_object_linkage +{ + /* Local variable. */ + DEBUG_LINKAGE_AUTOMATIC, + /* Static--either file static or function static, depending upon the + namespace is. */ + DEBUG_LINKAGE_STATIC, + /* Global. */ + DEBUG_LINKAGE_GLOBAL, + /* No linkage. */ + DEBUG_LINKAGE_NONE +}; + +/* A name in a namespace. */ + +struct debug_name +{ + /* Next name in this namespace. */ + struct debug_name *next; + /* Name. */ + const char *name; + /* Mark. This is used by debug_write. */ + unsigned int mark; + /* Kind of object. */ + enum debug_object_kind kind; + /* Linkage of object. */ + enum debug_object_linkage linkage; + /* Tagged union with additional information about the object. */ + union + { + /* DEBUG_OBJECT_TYPE. */ + struct debug_type *type; + /* DEBUG_OBJECT_TAG. */ + struct debug_type *tag; + /* DEBUG_OBJECT_VARIABLE. */ + struct debug_variable *variable; + /* DEBUG_OBJECT_FUNCTION. */ + struct debug_function *function; + /* DEBUG_OBJECT_INT_CONSTANT. */ + bfd_vma int_constant; + /* DEBUG_OBJECT_FLOAT_CONSTANT. */ + double float_constant; + /* DEBUG_OBJECT_TYPED_CONSTANT. */ + struct debug_typed_constant *typed_constant; + } u; +}; + +/* During debug_write, a linked list of these structures is used to + keep track of ID numbers that have been assigned to classes. */ + +struct debug_class_id +{ + /* Next ID number. */ + struct debug_class_id *next; + /* The type with the ID. */ + struct debug_type *type; + /* The tag; NULL if no tag. */ + const char *tag; +}; + +/* During debug_type_samep, a linked list of these structures is kept + on the stack to avoid infinite recursion. */ + +struct debug_type_compare_list +{ + /* Next type on list. */ + struct debug_type_compare_list *next; + /* The types we are comparing. */ + struct debug_type *t1; + struct debug_type *t2; +}; + +/* Local functions. */ + +static void debug_error PARAMS ((const char *)); +static struct debug_name *debug_add_to_namespace + PARAMS ((struct debug_handle *, struct debug_namespace **, const char *, + enum debug_object_kind, enum debug_object_linkage)); +static struct debug_name *debug_add_to_current_namespace + PARAMS ((struct debug_handle *, const char *, enum debug_object_kind, + enum debug_object_linkage)); +static struct debug_type *debug_make_type + PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int)); +static struct debug_type *debug_get_real_type PARAMS ((PTR, debug_type)); +static boolean debug_write_name + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_name *)); +static boolean debug_write_type + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_type *, struct debug_name *)); +static boolean debug_write_class_type + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_type *, const char *)); +static boolean debug_write_function + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + const char *, enum debug_object_linkage, struct debug_function *)); +static boolean debug_write_block + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_block *)); +static boolean debug_write_linenos + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + bfd_vma)); +static boolean debug_set_class_id + PARAMS ((struct debug_handle *, const char *, struct debug_type *)); +static boolean debug_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); +static boolean debug_class_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); + +/* Issue an error message. */ + +static void +debug_error (message) + const char *message; +{ + fprintf (stderr, "%s\n", message); +} + +/* Add an object to a namespace. */ + +static struct debug_name * +debug_add_to_namespace (info, nsp, name, kind, linkage) + struct debug_handle *info; + struct debug_namespace **nsp; + const char *name; + enum debug_object_kind kind; + enum debug_object_linkage linkage; +{ + struct debug_name *n; + struct debug_namespace *ns; + + n = (struct debug_name *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->name = name; + n->kind = kind; + n->linkage = linkage; + + ns = *nsp; + if (ns == NULL) + { + ns = (struct debug_namespace *) xmalloc (sizeof *ns); + memset (ns, 0, sizeof *ns); + + ns->tail = &ns->list; + + *nsp = ns; + } + + *ns->tail = n; + ns->tail = &n->next; + + return n; +} + +/* Add an object to the current namespace. */ + +static struct debug_name * +debug_add_to_current_namespace (info, name, kind, linkage) + struct debug_handle *info; + const char *name; + enum debug_object_kind kind; + enum debug_object_linkage linkage; +{ + struct debug_namespace **nsp; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error ("debug_add_to_current_namespace: no current file"); + return NULL; + } + + if (info->current_block != NULL) + nsp = &info->current_block->locals; + else + nsp = &info->current_file->globals; + + return debug_add_to_namespace (info, nsp, name, kind, linkage); +} + +/* Return a handle for debugging information. */ + +PTR +debug_init () +{ + struct debug_handle *ret; + + ret = (struct debug_handle *) xmalloc (sizeof *ret); + memset (ret, 0, sizeof *ret); + return (PTR) ret; +} + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +boolean +debug_set_filename (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_file *nfile; + struct debug_unit *nunit; + + if (name == NULL) + name = ""; + + nfile = (struct debug_file *) xmalloc (sizeof *nfile); + memset (nfile, 0, sizeof *nfile); + + nfile->filename = name; + + nunit = (struct debug_unit *) xmalloc (sizeof *nunit); + memset (nunit, 0, sizeof *nunit); + + nunit->files = nfile; + info->current_file = nfile; + + if (info->current_unit != NULL) + info->current_unit->next = nunit; + else + { + assert (info->units == NULL); + info->units = nunit; + } + + info->current_unit = nunit; + + info->current_function = NULL; + info->current_block = NULL; + info->current_lineno = NULL; + + return true; +} + +/* Change source files to the given file name. This is used for + include files in a single compilation unit. */ + +boolean +debug_start_source (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_file *f, **pf; + + if (name == NULL) + name = ""; + + if (info->current_unit == NULL) + { + debug_error ("debug_start_source: no debug_set_filename call"); + return false; + } + + for (f = info->current_unit->files; f != NULL; f = f->next) + { + if (f->filename[0] == name[0] + && f->filename[1] == name[1] + && strcmp (f->filename, name) == 0) + { + info->current_file = f; + return true; + } + } + + f = (struct debug_file *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->filename = name; + + for (pf = &info->current_file->next; + *pf != NULL; + pf = &(*pf)->next) + ; + *pf = f; + + info->current_file = f; + + return true; +} + +/* Record a function definition. This implicitly starts a function + block. The debug_type argument is the type of the return value. + The boolean indicates whether the function is globally visible. + The bfd_vma is the address of the start of the function. Currently + the parameter types are specified by calls to + debug_record_parameter. FIXME: There is no way to specify nested + functions. */ + +boolean +debug_record_function (handle, name, return_type, global, addr) + PTR handle; + const char *name; + debug_type return_type; + boolean global; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_function *f; + struct debug_block *b; + struct debug_name *n; + + if (name == NULL) + name = ""; + if (return_type == NULL) + return false; + + if (info->current_unit == NULL) + { + debug_error ("debug_record_function: no debug_set_filename call"); + return false; + } + + f = (struct debug_function *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->return_type = return_type; + + b = (struct debug_block *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->start = addr; + b->end = (bfd_vma) -1; + + f->blocks = b; + + info->current_function = f; + info->current_block = b; + + /* FIXME: If we could handle nested functions, this would be the + place: we would want to use a different namespace. */ + n = debug_add_to_namespace (info, + &info->current_file->globals, + name, + DEBUG_OBJECT_FUNCTION, + (global + ? DEBUG_LINKAGE_GLOBAL + : DEBUG_LINKAGE_STATIC)); + if (n == NULL) + return false; + + n->u.function = f; + + return true; +} + +/* Record a parameter for the current function. */ + +boolean +debug_record_parameter (handle, name, type, kind, val) + PTR handle; + const char *name; + debug_type type; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_parameter *p, **pp; + + if (name == NULL || type == NULL) + return false; + + if (info->current_unit == NULL + || info->current_function == NULL) + { + debug_error ("debug_record_parameter: no current function"); + return false; + } + + p = (struct debug_parameter *) xmalloc (sizeof *p); + memset (p, 0, sizeof *p); + + p->name = name; + p->type = type; + p->kind = kind; + p->val = val; + + for (pp = &info->current_function->parameters; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = p; + + return true; +} + +/* End a function. FIXME: This should handle function nesting. */ + +boolean +debug_end_function (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + if (info->current_unit == NULL + || info->current_block == NULL + || info->current_function == NULL) + { + debug_error ("debug_end_function: no current function"); + return false; + } + + if (info->current_block->parent != NULL) + { + debug_error ("debug_end_function: some blocks were not closed"); + return false; + } + + info->current_block->end = addr; + + info->current_function = NULL; + info->current_block = NULL; + + return true; +} + +/* Start a block in a function. All local information will be + recorded in this block, until the matching call to debug_end_block. + debug_start_block and debug_end_block may be nested. The bfd_vma + argument is the address at which this block starts. */ + +boolean +debug_start_block (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *b, **pb; + + /* We must always have a current block: debug_record_function sets + one up. */ + if (info->current_unit == NULL + || info->current_block == NULL) + { + debug_error ("debug_start_block: no current block"); + return false; + } + + b = (struct debug_block *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->parent = info->current_block; + b->start = addr; + b->end = (bfd_vma) -1; + + /* This new block is a child of the current block. */ + for (pb = &info->current_block->children; + *pb != NULL; + pb = &(*pb)->next) + ; + *pb = b; + + info->current_block = b; + + return true; +} + +/* Finish a block in a function. This matches the call to + debug_start_block. The argument is the address at which this block + ends. */ + +boolean +debug_end_block (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *parent; + + if (info->current_unit == NULL + || info->current_block == NULL) + { + debug_error ("debug_end_block: no current block"); + return false; + } + + parent = info->current_block->parent; + if (parent == NULL) + { + debug_error ("debug_end_block: attempt to close top level block"); + return false; + } + + info->current_block->end = addr; + + info->current_block = parent; + + return true; +} + +/* Associate a line number in the current source file and function + with a given address. */ + +boolean +debug_record_line (handle, lineno, addr) + PTR handle; + unsigned long lineno; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_lineno *l; + unsigned int i; + + if (info->current_unit == NULL) + { + debug_error ("debug_record_line: no current unit"); + return false; + } + + l = info->current_lineno; + if (l != NULL && l->file == info->current_file) + { + for (i = 0; i < DEBUG_LINENO_COUNT; i++) + { + if (l->linenos[i] == (unsigned long) -1) + { + l->linenos[i] = lineno; + l->addrs[i] = addr; + return true; + } + } + } + + /* If we get here, then either 1) there is no current_lineno + structure, which means this is the first line number in this + compilation unit, 2) the current_lineno structure is for a + different file, or 3) the current_lineno structure is full. + Regardless, we want to allocate a new debug_lineno structure, put + it in the right place, and make it the new current_lineno + structure. */ + + l = (struct debug_lineno *) xmalloc (sizeof *l); + memset (l, 0, sizeof *l); + + l->file = info->current_file; + l->linenos[0] = lineno; + l->addrs[0] = addr; + for (i = 1; i < DEBUG_LINENO_COUNT; i++) + l->linenos[i] = (unsigned long) -1; + + if (info->current_lineno != NULL) + info->current_lineno->next = l; + else + info->current_unit->linenos = l; + + info->current_lineno = l; + + return true; +} + +/* Start a named common block. This is a block of variables that may + move in memory. */ + +boolean +debug_start_common_block (handle, name) + PTR handle; + const char *name; +{ + /* FIXME */ + debug_error ("debug_start_common_block: not implemented"); + return false; +} + +/* End a named common block. */ + +boolean +debug_end_common_block (handle, name) + PTR handle; + const char *name; +{ + /* FIXME */ + debug_error ("debug_end_common_block: not implemented"); + return false; +} + +/* Record a named integer constant. */ + +boolean +debug_record_int_const (handle, name, val) + PTR handle; + const char *name; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + + if (name == NULL) + return false; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return false; + + n->u.int_constant = val; + + return true; +} + +/* Record a named floating point constant. */ + +boolean +debug_record_float_const (handle, name, val) + PTR handle; + const char *name; + double val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + + if (name == NULL) + return false; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return false; + + n->u.float_constant = val; + + return true; +} + +/* Record a typed constant with an integral value. */ + +boolean +debug_record_typed_const (handle, name, type, val) + PTR handle; + const char *name; + debug_type type; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + struct debug_typed_constant *tc; + + if (name == NULL || type == NULL) + return false; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return false; + + tc = (struct debug_typed_constant *) xmalloc (sizeof *tc); + memset (tc, 0, sizeof *tc); + + tc->type = type; + tc->val = val; + + n->u.typed_constant = tc; + + return true; +} + +/* Record a label. */ + +boolean +debug_record_label (handle, name, type, addr) + PTR handle; + const char *name; + debug_type type; + bfd_vma addr; +{ + /* FIXME. */ + debug_error ("debug_record_label not implemented"); + return false; +} + +/* Record a variable. */ + +boolean +debug_record_variable (handle, name, type, kind, val) + PTR handle; + const char *name; + debug_type type; + enum debug_var_kind kind; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_namespace **nsp; + enum debug_object_linkage linkage; + struct debug_name *n; + struct debug_variable *v; + + if (name == NULL || type == NULL) + return false; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error ("debug_record_variable: no current file"); + return false; + } + + if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) + { + nsp = &info->current_file->globals; + if (kind == DEBUG_GLOBAL) + linkage = DEBUG_LINKAGE_GLOBAL; + else + linkage = DEBUG_LINKAGE_STATIC; + } + else + { + if (info->current_block == NULL) + { + debug_error ("debug_record_variable: no current block"); + return false; + } + nsp = &info->current_block->locals; + linkage = DEBUG_LINKAGE_AUTOMATIC; + } + + n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage); + if (n == NULL) + return false; + + v = (struct debug_variable *) xmalloc (sizeof *v); + memset (v, 0, sizeof *v); + + v->kind = kind; + v->type = type; + v->val = val; + + n->u.variable = v; + + return true; +} + +/* Make a type with a given kind and size. */ + +/*ARGSUSED*/ +static struct debug_type * +debug_make_type (info, kind, size) + struct debug_handle *info; + enum debug_type_kind kind; + unsigned int size; +{ + struct debug_type *t; + + t = (struct debug_type *) xmalloc (sizeof *t); + memset (t, 0, sizeof *t); + + t->kind = kind; + t->size = size; + + return t; +} + +/* Make an indirect type which may be used as a placeholder for a type + which is referenced before it is defined. */ + +debug_type +debug_make_indirect_type (handle, slot, tag) + PTR handle; + debug_type *slot; + const char *tag; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_indirect_type *i; + + t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + i = (struct debug_indirect_type *) xmalloc (sizeof *i); + memset (i, 0, sizeof *i); + + i->slot = slot; + i->tag = tag; + + t->u.kindirect = i; + + return t; +} + +/* Make a void type. There is only one of these. */ + +debug_type +debug_make_void_type (handle) + PTR handle; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_VOID, 0); +} + +/* Make an integer type of a given size. The boolean argument is true + if the integer is unsigned. */ + +debug_type +debug_make_int_type (handle, size, unsignedp) + PTR handle; + unsigned int size; + boolean unsignedp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + t = debug_make_type (info, DEBUG_KIND_INT, size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kint = unsignedp; + + return t; +} + +/* Make a floating point type of a given size. FIXME: On some + platforms, like an Alpha, you probably need to be able to specify + the format. */ + +debug_type +debug_make_float_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_FLOAT, size); +} + +/* Make a boolean type of a given size. */ + +debug_type +debug_make_bool_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_BOOL, size); +} + +/* Make a complex type of a given size. */ + +debug_type +debug_make_complex_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_COMPLEX, size); +} + +/* Make a structure type. The second argument is true for a struct, + false for a union. The third argument is the size of the struct. + The fourth argument is a NULL terminated array of fields. */ + +debug_type +debug_make_struct_type (handle, structp, size, fields) + PTR handle; + boolean structp; + bfd_vma size; + debug_field *fields; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_class_type *c; + + t = debug_make_type (info, + structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION, + size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + c = (struct debug_class_type *) xmalloc (sizeof *c); + memset (c, 0, sizeof *c); + + c->fields = fields; + + t->u.kclass = c; + + return t; +} + +/* Make an object type. The first three arguments after the handle + are the same as for debug_make_struct_type. The next arguments are + a NULL terminated array of base classes, a NULL terminated array of + methods, the type of the object holding the virtual function table + if it is not this object, and a boolean which is true if this + object has its own virtual function table. */ + +debug_type +debug_make_object_type (handle, structp, size, fields, baseclasses, + methods, vptrbase, ownvptr) + PTR handle; + boolean structp; + bfd_vma size; + debug_field *fields; + debug_baseclass *baseclasses; + debug_method *methods; + debug_type vptrbase; + boolean ownvptr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_class_type *c; + + t = debug_make_type (info, + structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS, + size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + c = (struct debug_class_type *) xmalloc (sizeof *c); + memset (c, 0, sizeof *c); + + c->fields = fields; + c->baseclasses = baseclasses; + c->methods = methods; + if (ownvptr) + c->vptrbase = t; + else + c->vptrbase = vptrbase; + + t->u.kclass = c; + + return t; +} + +/* Make an enumeration type. The arguments are a null terminated + array of strings, and an array of corresponding values. */ + +debug_type +debug_make_enum_type (handle, names, values) + PTR handle; + const char **names; + bfd_signed_vma *values; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_enum_type *e; + + t = debug_make_type (info, DEBUG_KIND_ENUM, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + e = (struct debug_enum_type *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + + e->names = names; + e->values = values; + + t->u.kenum = e; + + return t; +} + +/* Make a pointer to a given type. */ + +debug_type +debug_make_pointer_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + if (type->pointer != DEBUG_TYPE_NULL) + return type->pointer; + + t = debug_make_type (info, DEBUG_KIND_POINTER, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kpointer = type; + + type->pointer = t; + + return t; +} + +/* Make a function returning a given type. FIXME: We should be able + to record the parameter types. */ + +debug_type +debug_make_function_type (handle, type, arg_types, varargs) + PTR handle; + debug_type type; + debug_type *arg_types; + boolean varargs; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_function_type *f; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + f = (struct debug_function_type *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->return_type = type; + f->arg_types = arg_types; + f->varargs = varargs; + + t->u.kfunction = f; + + return t; +} + +/* Make a reference to a given type. */ + +debug_type +debug_make_reference_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kreference = type; + + return t; +} + +/* Make a range of a given type from a lower to an upper bound. */ + +debug_type +debug_make_range_type (handle, type, lower, upper) + PTR handle; + debug_type type; + bfd_signed_vma lower; + bfd_signed_vma upper; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_range_type *r; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_RANGE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + r = (struct debug_range_type *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + + r->type = type; + r->lower = lower; + r->upper = upper; + + t->u.krange = r; + + return t; +} + +/* Make an array type. The second argument is the type of an element + of the array. The third argument is the type of a range of the + array. The fourth and fifth argument are the lower and upper + bounds, respectively. The sixth argument is true if this array is + actually a string, as in C. */ + +debug_type +debug_make_array_type (handle, element_type, range_type, lower, upper, + stringp) + PTR handle; + debug_type element_type; + debug_type range_type; + bfd_signed_vma lower; + bfd_signed_vma upper; + boolean stringp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_array_type *a; + + if (element_type == NULL || range_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_ARRAY, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + a = (struct debug_array_type *) xmalloc (sizeof *a); + memset (a, 0, sizeof *a); + + a->element_type = element_type; + a->range_type = range_type; + a->lower = lower; + a->upper = upper; + a->stringp = stringp; + + t->u.karray = a; + + return t; +} + +/* Make a set of a given type. For example, a Pascal set type. The + boolean argument is true if this set is actually a bitstring, as in + CHILL. */ + +debug_type +debug_make_set_type (handle, type, bitstringp) + PTR handle; + debug_type type; + boolean bitstringp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_set_type *s; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_SET, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + s = (struct debug_set_type *) xmalloc (sizeof *s); + memset (s, 0, sizeof *s); + + s->type = type; + s->bitstringp = bitstringp; + + t->u.kset = s; + + return t; +} + +/* Make a type for a pointer which is relative to an object. The + second argument is the type of the object to which the pointer is + relative. The third argument is the type that the pointer points + to. */ + +debug_type +debug_make_offset_type (handle, base_type, target_type) + PTR handle; + debug_type base_type; + debug_type target_type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_offset_type *o; + + if (base_type == NULL || target_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_OFFSET, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + o = (struct debug_offset_type *) xmalloc (sizeof *o); + memset (o, 0, sizeof *o); + + o->base_type = base_type; + o->target_type = target_type; + + t->u.koffset = o; + + return t; +} + +/* Make a type for a method function. The second argument is the + return type, the third argument is the domain, and the fourth + argument is a NULL terminated array of argument types. */ + +debug_type +debug_make_method_type (handle, return_type, domain_type, arg_types, varargs) + PTR handle; + debug_type return_type; + debug_type domain_type; + debug_type *arg_types; + boolean varargs; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_method_type *m; + + if (return_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_METHOD, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + m = (struct debug_method_type *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->return_type = return_type; + m->domain_type = domain_type; + m->arg_types = arg_types; + m->varargs = varargs; + + t->u.kmethod = m; + + return t; +} + +/* Make a const qualified version of a given type. */ + +debug_type +debug_make_const_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_CONST, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kconst = type; + + return t; +} + +/* Make a volatile qualified version of a given type. */ + +debug_type +debug_make_volatile_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kvolatile = type; + + return t; +} + +/* Make an undefined tagged type. For example, a struct which has + been mentioned, but not defined. */ + +debug_type +debug_make_undefined_tagged_type (handle, name, kind) + PTR handle; + const char *name; + enum debug_type_kind kind; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (name == NULL) + return DEBUG_TYPE_NULL; + + switch (kind) + { + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + case DEBUG_KIND_ENUM: + break; + + default: + debug_error ("debug_make_undefined_type: unsupported kind"); + return DEBUG_TYPE_NULL; + } + + t = debug_make_type (info, kind, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + return debug_tag_type (handle, name, t); +} + +/* Make a base class for an object. The second argument is the base + class type. The third argument is the bit position of this base + class in the object (always 0 unless doing multiple inheritance). + The fourth argument is whether this is a virtual class. The fifth + argument is the visibility of the base class. */ + +/*ARGSUSED*/ +debug_baseclass +debug_make_baseclass (handle, type, bitpos, virtual, visibility) + PTR handle; + debug_type type; + bfd_vma bitpos; + boolean virtual; + enum debug_visibility visibility; +{ + struct debug_baseclass *b; + + b = (struct debug_baseclass *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->type = type; + b->bitpos = bitpos; + b->virtual = virtual; + b->visibility = visibility; + + return b; +} + +/* Make a field for a struct. The second argument is the name. The + third argument is the type of the field. The fourth argument is + the bit position of the field. The fifth argument is the size of + the field (it may be zero). The sixth argument is the visibility + of the field. */ + +/*ARGSUSED*/ +debug_field +debug_make_field (handle, name, type, bitpos, bitsize, visibility) + PTR handle; + const char *name; + debug_type type; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct debug_field *f; + + f = (struct debug_field *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->name = name; + f->type = type; + f->static_member = false; + f->u.f.bitpos = bitpos; + f->u.f.bitsize = bitsize; + f->visibility = visibility; + + return f; +} + +/* Make a static member of an object. The second argument is the + name. The third argument is the type of the member. The fourth + argument is the physical name of the member (i.e., the name as a + global variable). The fifth argument is the visibility of the + member. */ + +/*ARGSUSED*/ +debug_field +debug_make_static_member (handle, name, type, physname, visibility) + PTR handle; + const char *name; + debug_type type; + const char *physname; + enum debug_visibility visibility; +{ + struct debug_field *f; + + f = (struct debug_field *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->name = name; + f->type = type; + f->static_member = true; + f->u.s.physname = physname; + f->visibility = visibility; + + return f; +} + +/* Make a method. The second argument is the name, and the third + argument is a NULL terminated array of method variants. */ + +/*ARGSUSED*/ +debug_method +debug_make_method (handle, name, variants) + PTR handle; + const char *name; + debug_method_variant *variants; +{ + struct debug_method *m; + + m = (struct debug_method *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->name = name; + m->variants = variants; + + return m; +} + +/* Make a method argument. The second argument is the real name of + the function. The third argument is the type of the function. The + fourth argument is the visibility. The fifth argument is whether + this is a const function. The sixth argument is whether this is a + volatile function. The seventh argument is the offset in the + virtual function table, if any. The eighth argument is the virtual + function context. FIXME: Are the const and volatile arguments + necessary? Could we just use debug_make_const_type? */ + +/*ARGSUSED*/ +debug_method_variant +debug_make_method_variant (handle, physname, type, visibility, constp, + volatilep, voffset, context) + PTR handle; + const char *physname; + debug_type type; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; + bfd_vma voffset; + debug_type context; +{ + struct debug_method_variant *m; + + m = (struct debug_method_variant *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->physname = physname; + m->type = type; + m->visibility = visibility; + m->constp = constp; + m->volatilep = volatilep; + m->voffset = voffset; + m->context = context; + + return m; +} + +/* Make a static method argument. The arguments are the same as for + debug_make_method_variant, except that the last two are omitted + since a static method can not also be virtual. */ + +debug_method_variant +debug_make_static_method_variant (handle, physname, type, visibility, + constp, volatilep) + PTR handle; + const char *physname; + debug_type type; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; +{ + struct debug_method_variant *m; + + m = (struct debug_method_variant *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->physname = physname; + m->type = type; + m->visibility = visibility; + m->constp = constp; + m->volatilep = volatilep; + m->voffset = VOFFSET_STATIC_METHOD; + + return m; +} + +/* Name a type. */ + +debug_type +debug_name_type (handle, name, type) + PTR handle; + const char *name; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_named_type *n; + struct debug_name *nm; + + if (name == NULL || type == NULL) + return DEBUG_TYPE_NULL; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error ("debug_name_type: no current file"); + return DEBUG_TYPE_NULL; + /* return false; */ + } + + t = debug_make_type (info, DEBUG_KIND_NAMED, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + n = (struct debug_named_type *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = type; + + t->u.knamed = n; + + /* We always add the name to the global namespace. This is probably + wrong in some cases, but it seems to be right for stabs. FIXME. */ + + nm = debug_add_to_namespace (info, &info->current_file->globals, name, + DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE); + if (nm == NULL) + return DEBUG_TYPE_NULL; + + nm->u.type = t; + + n->name = nm; + + return t; +} + +/* Tag a type. */ + +debug_type +debug_tag_type (handle, name, type) + PTR handle; + const char *name; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_named_type *n; + struct debug_name *nm; + + if (name == NULL || type == NULL) + return DEBUG_TYPE_NULL; + + if (info->current_file == NULL) + { + debug_error ("debug_tag_type: no current file"); + return DEBUG_TYPE_NULL; + } + + if (type->kind == DEBUG_KIND_TAGGED) + { + if (strcmp (type->u.knamed->name->name, name) == 0) + return type; + debug_error ("debug_tag_type: extra tag attempted"); + return DEBUG_TYPE_NULL; + } + + t = debug_make_type (info, DEBUG_KIND_TAGGED, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + n = (struct debug_named_type *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = type; + + t->u.knamed = n; + + /* We keep a global namespace of tags for each compilation unit. I + don't know if that is the right thing to do. */ + + nm = debug_add_to_namespace (info, &info->current_file->globals, name, + DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE); + if (nm == NULL) + return DEBUG_TYPE_NULL; + + nm->u.tag = t; + + n->name = nm; + + return t; +} + +/* Record the size of a given type. */ + +/*ARGSUSED*/ +boolean +debug_record_type_size (handle, type, size) + PTR handle; + debug_type type; + unsigned int size; +{ +#if 0 + if (type->size != 0 && type->size != size) + fprintf (stderr, "Warning: changing type size from %d to %d\n", + type->size, size); +#endif + + type->size = size; + + return true; +} + +/* Find a named type. */ + +debug_type +debug_find_named_type (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *b; + struct debug_file *f; + + /* We only search the current compilation unit. I don't know if + this is right or not. */ + + if (info->current_unit == NULL) + { + debug_error ("debug_find_named_type: no current compilation unit"); + return DEBUG_TYPE_NULL; + } + + for (b = info->current_block; b != NULL; b = b->parent) + { + if (b->locals != NULL) + { + struct debug_name *n; + + for (n = b->locals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TYPE + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.type; + } + } + } + + for (f = info->current_unit->files; f != NULL; f = f->next) + { + if (f->globals != NULL) + { + struct debug_name *n; + + for (n = f->globals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TYPE + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.type; + } + } + } + + return DEBUG_TYPE_NULL; +} + +/* Find a tagged type. */ + +debug_type +debug_find_tagged_type (handle, name, kind) + PTR handle; + const char *name; + enum debug_type_kind kind; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_unit *u; + + /* We search the globals of all the compilation units. I don't know + if this is correct or not. It would be easy to change. */ + + for (u = info->units; u != NULL; u = u->next) + { + struct debug_file *f; + + for (f = u->files; f != NULL; f = f->next) + { + struct debug_name *n; + + if (f->globals != NULL) + { + for (n = f->globals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TAG + && (kind == DEBUG_KIND_ILLEGAL + || n->u.tag->kind == kind) + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.tag; + } + } + } + } + + return DEBUG_TYPE_NULL; +} + +/* Get a base type. */ + +static struct debug_type * +debug_get_real_type (handle, type) + PTR handle; + debug_type type; +{ + switch (type->kind) + { + default: + return type; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot != NULL) + return debug_get_real_type (handle, *type->u.kindirect->slot); + return type; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_real_type (handle, type->u.knamed->type); + } + /*NOTREACHED*/ +} + +/* Get the kind of a type. */ + +enum debug_type_kind +debug_get_type_kind (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return DEBUG_KIND_ILLEGAL; + type = debug_get_real_type (handle, type); + return type->kind; +} + +/* Get the name of a type. */ + +const char * +debug_get_type_name (handle, type) + PTR handle; + debug_type type; +{ + if (type->kind == DEBUG_KIND_INDIRECT) + { + if (*type->u.kindirect->slot != NULL) + return debug_get_type_name (handle, *type->u.kindirect->slot); + return type->u.kindirect->tag; + } + if (type->kind == DEBUG_KIND_NAMED + || type->kind == DEBUG_KIND_TAGGED) + return type->u.knamed->name->name; + return NULL; +} + +/* Get the size of a type. */ + +bfd_vma +debug_get_type_size (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return 0; + + /* We don't call debug_get_real_type, because somebody might have + called debug_record_type_size on a named or indirect type. */ + + if (type->size != 0) + return type->size; + + switch (type->kind) + { + default: + return 0; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot != NULL) + return debug_get_type_size (handle, *type->u.kindirect->slot); + return 0; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_type_size (handle, type->u.knamed->type); + } + /*NOTREACHED*/ +} + +/* Get the return type of a function or method type. */ + +debug_type +debug_get_return_type (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return DEBUG_TYPE_NULL; + type = debug_get_real_type (handle, type); + switch (type->kind) + { + default: + return DEBUG_TYPE_NULL; + case DEBUG_KIND_FUNCTION: + return type->u.kfunction->return_type; + case DEBUG_KIND_METHOD: + return type->u.kmethod->return_type; + } + /*NOTREACHED*/ +} + +/* Get the parameter types of a function or method type (except that + we don't currently store the parameter types of a function). */ + +const debug_type * +debug_get_parameter_types (handle, type, pvarargs) + PTR handle; + debug_type type; + boolean *pvarargs; +{ + if (type == NULL) + return NULL; + type = debug_get_real_type (handle, type); + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_FUNCTION: + *pvarargs = type->u.kfunction->varargs; + return type->u.kfunction->arg_types; + case DEBUG_KIND_METHOD: + *pvarargs = type->u.kmethod->varargs; + return type->u.kmethod->arg_types; + } + /*NOTREACHED*/ +} + +/* Get the target type of a type. */ + +debug_type +debug_get_target_type (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return NULL; + type = debug_get_real_type (handle, type); + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_POINTER: + return type->u.kpointer; + case DEBUG_KIND_REFERENCE: + return type->u.kreference; + case DEBUG_KIND_CONST: + return type->u.kconst; + case DEBUG_KIND_VOLATILE: + return type->u.kvolatile; + } + /*NOTREACHED*/ +} + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +const debug_field * +debug_get_fields (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return NULL; + type = debug_get_real_type (handle, type); + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + return type->u.kclass->fields; + } + /*NOTREACHED*/ +} + +/* Get the type of a field. */ + +/*ARGSUSED*/ +debug_type +debug_get_field_type (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL) + return NULL; + return field->type; +} + +/* Get the name of a field. */ + +/*ARGSUSED*/ +const char * +debug_get_field_name (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL) + return NULL; + return field->name; +} + +/* Get the bit position of a field. */ + +/*ARGSUSED*/ +bfd_vma +debug_get_field_bitpos (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitpos; +} + +/* Get the bit size of a field. */ + +/*ARGSUSED*/ +bfd_vma +debug_get_field_bitsize (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitsize; +} + +/* Get the visibility of a field. */ + +/*ARGSUSED*/ +enum debug_visibility +debug_get_field_visibility (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL) + return DEBUG_VISIBILITY_IGNORE; + return field->visibility; +} + +/* Get the physical name of a field. */ + +const char * +debug_get_field_physname (handle, field) + PTR handle; + debug_field field; +{ + if (field == NULL || ! field->static_member) + return NULL; + return field->u.s.physname; +} + +/* Write out the debugging information. This is given a handle to + debugging information, and a set of function pointers to call. */ + +boolean +debug_write (handle, fns, fhandle) + PTR handle; + const struct debug_write_fns *fns; + PTR fhandle; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_unit *u; + + /* We use a mark to tell whether we have already written out a + particular name. We use an integer, so that we don't have to + clear the mark fields if we happen to write out the same + information more than once. */ + ++info->mark; + + /* The base_id field holds an ID value which will never be used, so + that we can tell whether we have assigned an ID during this call + to debug_write. */ + info->base_id = info->class_id; + + /* We keep a linked list of classes for which was have assigned ID's + during this call to debug_write. */ + info->id_list = NULL; + + for (u = info->units; u != NULL; u = u->next) + { + struct debug_file *f; + boolean first_file; + + info->current_write_lineno = u->linenos; + info->current_write_lineno_index = 0; + + if (! (*fns->start_compilation_unit) (fhandle, u->files->filename)) + return false; + + first_file = true; + for (f = u->files; f != NULL; f = f->next) + { + struct debug_name *n; + + if (first_file) + first_file = false; + else + { + if (! (*fns->start_source) (fhandle, f->filename)) + return false; + } + + if (f->globals != NULL) + { + for (n = f->globals->list; n != NULL; n = n->next) + { + if (! debug_write_name (info, fns, fhandle, n)) + return false; + } + } + } + + /* Output any line number information which hasn't already been + handled. */ + if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1)) + return false; + } + + return true; +} + +/* Write out an element in a namespace. */ + +static boolean +debug_write_name (info, fns, fhandle, n) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_name *n; +{ + switch (n->kind) + { + case DEBUG_OBJECT_TYPE: + if (! debug_write_type (info, fns, fhandle, n->u.type, n) + || ! (*fns->typdef) (fhandle, n->name)) + return false; + return true; + case DEBUG_OBJECT_TAG: + if (! debug_write_type (info, fns, fhandle, n->u.tag, n)) + return false; + return (*fns->tag) (fhandle, n->name); + case DEBUG_OBJECT_VARIABLE: + if (! debug_write_type (info, fns, fhandle, n->u.variable->type, + (struct debug_name *) NULL)) + return false; + return (*fns->variable) (fhandle, n->name, n->u.variable->kind, + n->u.variable->val); + case DEBUG_OBJECT_FUNCTION: + return debug_write_function (info, fns, fhandle, n->name, + n->linkage, n->u.function); + case DEBUG_OBJECT_INT_CONSTANT: + return (*fns->int_constant) (fhandle, n->name, n->u.int_constant); + case DEBUG_OBJECT_FLOAT_CONSTANT: + return (*fns->float_constant) (fhandle, n->name, n->u.float_constant); + case DEBUG_OBJECT_TYPED_CONSTANT: + if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type, + (struct debug_name *) NULL)) + return false; + return (*fns->typed_constant) (fhandle, n->name, + n->u.typed_constant->val); + default: + abort (); + return false; + } + /*NOTREACHED*/ +} + +/* Write out a type. If the type is DEBUG_KIND_NAMED or + DEBUG_KIND_TAGGED, then the name argument is the name for which we + are about to call typedef or tag. If the type is anything else, + then the name argument is a tag from a DEBUG_KIND_TAGGED type which + points to this one. */ + +static boolean +debug_write_type (info, fns, fhandle, type, name) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_type *type; + struct debug_name *name; +{ + unsigned int i; + int is; + const char *tag; + + /* If we have a name for this type, just output it. We only output + typedef names after they have been defined. We output type tags + whenever we are not actually defining them. */ + if ((type->kind == DEBUG_KIND_NAMED + || type->kind == DEBUG_KIND_TAGGED) + && (type->u.knamed->name->mark == info->mark + || (type->kind == DEBUG_KIND_TAGGED + && type->u.knamed->name != name))) + { + if (type->kind == DEBUG_KIND_NAMED) + return (*fns->typedef_type) (fhandle, type->u.knamed->name->name); + else + { + struct debug_type *real; + unsigned int id; + + real = debug_get_real_type ((PTR) info, type); + id = 0; + if ((real->kind == DEBUG_KIND_STRUCT + || real->kind == DEBUG_KIND_UNION + || real->kind == DEBUG_KIND_CLASS + || real->kind == DEBUG_KIND_UNION_CLASS) + && real->u.kclass != NULL) + { + if (real->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, + type->u.knamed->name->name, + real)) + return false; + } + id = real->u.kclass->id; + } + + return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id, + real->kind); + } + } + + /* Mark the name after we have already looked for a known name, so + that we don't just define a type in terms of itself. We need to + mark the name here so that a struct containing a pointer to + itself will work. */ + if (name != NULL) + name->mark = info->mark; + + tag = NULL; + if (name != NULL + && type->kind != DEBUG_KIND_NAMED + && type->kind != DEBUG_KIND_TAGGED) + { + assert (name->kind == DEBUG_OBJECT_TAG); + tag = name->name; + } + + switch (type->kind) + { + case DEBUG_KIND_ILLEGAL: + debug_error ("debug_write_type: illegal type encountered"); + return false; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) + return (*fns->empty_type) (fhandle); + return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, + name); + case DEBUG_KIND_VOID: + return (*fns->void_type) (fhandle); + case DEBUG_KIND_INT: + return (*fns->int_type) (fhandle, type->size, type->u.kint); + case DEBUG_KIND_FLOAT: + return (*fns->float_type) (fhandle, type->size); + case DEBUG_KIND_COMPLEX: + return (*fns->complex_type) (fhandle, type->size); + case DEBUG_KIND_BOOL: + return (*fns->bool_type) (fhandle, type->size); + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + if (type->u.kclass != NULL) + { + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return false; + } + + if (info->mark == type->u.kclass->mark) + { + /* We are currently outputting this struct, or we have + already output it. I don't know if this can happen, + but it can happen for a class. */ + assert (type->u.kclass->id > info->base_id); + return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, + type->kind); + } + type->u.kclass->mark = info->mark; + } + + if (! (*fns->start_struct_type) (fhandle, tag, + (type->u.kclass != NULL + ? type->u.kclass->id + : 0), + type->kind == DEBUG_KIND_STRUCT, + type->size)) + return false; + if (type->u.kclass != NULL + && type->u.kclass->fields != NULL) + { + for (i = 0; type->u.kclass->fields[i] != NULL; i++) + { + struct debug_field *f; + + f = type->u.kclass->fields[i]; + if (! debug_write_type (info, fns, fhandle, f->type, + (struct debug_name *) NULL) + || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, + f->u.f.bitsize, f->visibility)) + return false; + } + } + return (*fns->end_struct_type) (fhandle); + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + return debug_write_class_type (info, fns, fhandle, type, tag); + case DEBUG_KIND_ENUM: + if (type->u.kenum == NULL) + return (*fns->enum_type) (fhandle, tag, (const char **) NULL, + (bfd_signed_vma *) NULL); + return (*fns->enum_type) (fhandle, tag, type->u.kenum->names, + type->u.kenum->values); + case DEBUG_KIND_POINTER: + if (! debug_write_type (info, fns, fhandle, type->u.kpointer, + (struct debug_name *) NULL)) + return false; + return (*fns->pointer_type) (fhandle); + case DEBUG_KIND_FUNCTION: + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->return_type, + (struct debug_name *) NULL)) + return false; + if (type->u.kfunction->arg_types == NULL) + is = -1; + else + { + for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->arg_types[is], + (struct debug_name *) NULL)) + return false; + } + return (*fns->function_type) (fhandle, is, + type->u.kfunction->varargs); + case DEBUG_KIND_REFERENCE: + if (! debug_write_type (info, fns, fhandle, type->u.kreference, + (struct debug_name *) NULL)) + return false; + return (*fns->reference_type) (fhandle); + case DEBUG_KIND_RANGE: + if (! debug_write_type (info, fns, fhandle, type->u.krange->type, + (struct debug_name *) NULL)) + return false; + return (*fns->range_type) (fhandle, type->u.krange->lower, + type->u.krange->upper); + case DEBUG_KIND_ARRAY: + if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type, + (struct debug_name *) NULL) + || ! debug_write_type (info, fns, fhandle, + type->u.karray->range_type, + (struct debug_name *) NULL)) + return false; + return (*fns->array_type) (fhandle, type->u.karray->lower, + type->u.karray->upper, + type->u.karray->stringp); + case DEBUG_KIND_SET: + if (! debug_write_type (info, fns, fhandle, type->u.kset->type, + (struct debug_name *) NULL)) + return false; + return (*fns->set_type) (fhandle, type->u.kset->bitstringp); + case DEBUG_KIND_OFFSET: + if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type, + (struct debug_name *) NULL) + || ! debug_write_type (info, fns, fhandle, + type->u.koffset->target_type, + (struct debug_name *) NULL)) + return false; + return (*fns->offset_type) (fhandle); + case DEBUG_KIND_METHOD: + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->return_type, + (struct debug_name *) NULL)) + return false; + if (type->u.kmethod->arg_types == NULL) + is = -1; + else + { + for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->arg_types[is], + (struct debug_name *) NULL)) + return false; + } + if (type->u.kmethod->domain_type != NULL) + { + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->domain_type, + (struct debug_name *) NULL)) + return false; + } + return (*fns->method_type) (fhandle, + type->u.kmethod->domain_type != NULL, + is, + type->u.kmethod->varargs); + case DEBUG_KIND_CONST: + if (! debug_write_type (info, fns, fhandle, type->u.kconst, + (struct debug_name *) NULL)) + return false; + return (*fns->const_type) (fhandle); + case DEBUG_KIND_VOLATILE: + if (! debug_write_type (info, fns, fhandle, type->u.kvolatile, + (struct debug_name *) NULL)) + return false; + return (*fns->volatile_type) (fhandle); + case DEBUG_KIND_NAMED: + return debug_write_type (info, fns, fhandle, type->u.knamed->type, + (struct debug_name *) NULL); + case DEBUG_KIND_TAGGED: + return debug_write_type (info, fns, fhandle, type->u.knamed->type, + type->u.knamed->name); + default: + abort (); + return false; + } +} + +/* Write out a class type. */ + +static boolean +debug_write_class_type (info, fns, fhandle, type, tag) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_type *type; + const char *tag; +{ + unsigned int i; + unsigned int id; + struct debug_type *vptrbase; + + if (type->u.kclass == NULL) + { + id = 0; + vptrbase = NULL; + } + else + { + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return false; + } + + if (info->mark == type->u.kclass->mark) + { + /* We are currently outputting this class, or we have + already output it. This can happen when there are + methods for an anonymous class. */ + assert (type->u.kclass->id > info->base_id); + return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, + type->kind); + } + type->u.kclass->mark = info->mark; + id = type->u.kclass->id; + + vptrbase = type->u.kclass->vptrbase; + if (vptrbase != NULL && vptrbase != type) + { + if (! debug_write_type (info, fns, fhandle, vptrbase, + (struct debug_name *) NULL)) + return false; + } + } + + if (! (*fns->start_class_type) (fhandle, tag, id, + type->kind == DEBUG_KIND_CLASS, + type->size, + vptrbase != NULL, + vptrbase == type)) + return false; + + if (type->u.kclass != NULL) + { + if (type->u.kclass->fields != NULL) + { + for (i = 0; type->u.kclass->fields[i] != NULL; i++) + { + struct debug_field *f; + + f = type->u.kclass->fields[i]; + if (! debug_write_type (info, fns, fhandle, f->type, + (struct debug_name *) NULL)) + return false; + if (f->static_member) + { + if (! (*fns->class_static_member) (fhandle, f->name, + f->u.s.physname, + f->visibility)) + return false; + } + else + { + if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, + f->u.f.bitsize, f->visibility)) + return false; + } + } + } + + if (type->u.kclass->baseclasses != NULL) + { + for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++) + { + struct debug_baseclass *b; + + b = type->u.kclass->baseclasses[i]; + if (! debug_write_type (info, fns, fhandle, b->type, + (struct debug_name *) NULL)) + return false; + if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual, + b->visibility)) + return false; + } + } + + if (type->u.kclass->methods != NULL) + { + for (i = 0; type->u.kclass->methods[i] != NULL; i++) + { + struct debug_method *m; + unsigned int j; + + m = type->u.kclass->methods[i]; + if (! (*fns->class_start_method) (fhandle, m->name)) + return false; + for (j = 0; m->variants[j] != NULL; j++) + { + struct debug_method_variant *v; + + v = m->variants[j]; + if (v->context != NULL) + { + if (! debug_write_type (info, fns, fhandle, v->context, + (struct debug_name *) NULL)) + return false; + } + if (! debug_write_type (info, fns, fhandle, v->type, + (struct debug_name *) NULL)) + return false; + if (v->voffset != VOFFSET_STATIC_METHOD) + { + if (! (*fns->class_method_variant) (fhandle, v->physname, + v->visibility, + v->constp, + v->volatilep, + v->voffset, + v->context != NULL)) + return false; + } + else + { + if (! (*fns->class_static_method_variant) (fhandle, + v->physname, + v->visibility, + v->constp, + v->volatilep)) + return false; + } + } + if (! (*fns->class_end_method) (fhandle)) + return false; + } + } + } + + return (*fns->end_class_type) (fhandle); +} + +/* Write out information for a function. */ + +static boolean +debug_write_function (info, fns, fhandle, name, linkage, function) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + const char *name; + enum debug_object_linkage linkage; + struct debug_function *function; +{ + struct debug_parameter *p; + struct debug_block *b; + + if (! debug_write_linenos (info, fns, fhandle, function->blocks->start)) + return false; + + if (! debug_write_type (info, fns, fhandle, function->return_type, + (struct debug_name *) NULL)) + return false; + + if (! (*fns->start_function) (fhandle, name, + linkage == DEBUG_LINKAGE_GLOBAL)) + return false; + + for (p = function->parameters; p != NULL; p = p->next) + { + if (! debug_write_type (info, fns, fhandle, p->type, + (struct debug_name *) NULL) + || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val)) + return false; + } + + for (b = function->blocks; b != NULL; b = b->next) + { + if (! debug_write_block (info, fns, fhandle, b)) + return false; + } + + return (*fns->end_function) (fhandle); +} + +/* Write out information for a block. */ + +static boolean +debug_write_block (info, fns, fhandle, block) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_block *block; +{ + struct debug_name *n; + struct debug_block *b; + + if (! debug_write_linenos (info, fns, fhandle, block->start)) + return false; + + /* I can't see any point to writing out a block with no local + variables, so we don't bother, except for the top level block. */ + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->start_block) (fhandle, block->start)) + return false; + } + + if (block->locals != NULL) + { + for (n = block->locals->list; n != NULL; n = n->next) + { + if (! debug_write_name (info, fns, fhandle, n)) + return false; + } + } + + for (b = block->children; b != NULL; b = b->next) + { + if (! debug_write_block (info, fns, fhandle, b)) + return false; + } + + if (! debug_write_linenos (info, fns, fhandle, block->end)) + return false; + + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->end_block) (fhandle, block->end)) + return false; + } + + return true; +} + +/* Write out line number information up to ADDRESS. */ + +static boolean +debug_write_linenos (info, fns, fhandle, address) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + bfd_vma address; +{ + while (info->current_write_lineno != NULL) + { + struct debug_lineno *l; + + l = info->current_write_lineno; + + while (info->current_write_lineno_index < DEBUG_LINENO_COUNT) + { + if (l->linenos[info->current_write_lineno_index] + == (unsigned long) -1) + break; + + if (l->addrs[info->current_write_lineno_index] >= address) + return true; + + if (! (*fns->lineno) (fhandle, l->file->filename, + l->linenos[info->current_write_lineno_index], + l->addrs[info->current_write_lineno_index])) + return false; + + ++info->current_write_lineno_index; + } + + info->current_write_lineno = l->next; + info->current_write_lineno_index = 0; + } + + return true; +} + +/* Get the ID number for a class. If during the same call to + debug_write we find a struct with the same definition with the same + name, we use the same ID. This type of things happens because the + same struct will be defined by multiple compilation units. */ + +static boolean +debug_set_class_id (info, tag, type) + struct debug_handle *info; + const char *tag; + struct debug_type *type; +{ + struct debug_class_type *c; + struct debug_class_id *l; + + assert (type->kind == DEBUG_KIND_STRUCT + || type->kind == DEBUG_KIND_UNION + || type->kind == DEBUG_KIND_CLASS + || type->kind == DEBUG_KIND_UNION_CLASS); + + c = type->u.kclass; + + if (c->id > info->base_id) + return true; + + for (l = info->id_list; l != NULL; l = l->next) + { + if (l->type->kind != type->kind) + continue; + + if (tag == NULL) + { + if (l->tag != NULL) + continue; + } + else + { + if (l->tag == NULL + || l->tag[0] != tag[0] + || strcmp (l->tag, tag) != 0) + continue; + } + + if (debug_type_samep (info, l->type, type)) + { + c->id = l->type->u.kclass->id; + return true; + } + } + + /* There are no identical types. Use a new ID, and add it to the + list. */ + ++info->class_id; + c->id = info->class_id; + + l = (struct debug_class_id *) xmalloc (sizeof *l); + memset (l, 0, sizeof *l); + + l->type = type; + l->tag = tag; + + l->next = info->id_list; + info->id_list = l; + + return true; +} + +/* See if two types are the same. At this point, we don't care about + tags and the like. */ + +static boolean +debug_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_type_compare_list *l; + struct debug_type_compare_list top; + boolean ret; + + if (t1 == NULL) + return t2 == NULL; + if (t2 == NULL) + return false; + + while (t1->kind == DEBUG_KIND_INDIRECT) + { + t1 = *t1->u.kindirect->slot; + if (t1 == NULL) + return false; + } + while (t2->kind == DEBUG_KIND_INDIRECT) + { + t2 = *t2->u.kindirect->slot; + if (t2 == NULL) + return false; + } + + if (t1 == t2) + return true; + + /* As a special case, permit a typedef to match a tag, since C++ + debugging output will sometimes add a typedef where C debugging + output will not. */ + if (t1->kind == DEBUG_KIND_NAMED + && t2->kind == DEBUG_KIND_TAGGED) + return debug_type_samep (info, t1->u.knamed->type, t2); + else if (t1->kind == DEBUG_KIND_TAGGED + && t2->kind == DEBUG_KIND_NAMED) + return debug_type_samep (info, t1, t2->u.knamed->type); + + if (t1->kind != t2->kind + || t1->size != t2->size) + return false; + + /* Get rid of the trivial cases first. */ + switch (t1->kind) + { + default: + break; + case DEBUG_KIND_VOID: + case DEBUG_KIND_FLOAT: + case DEBUG_KIND_COMPLEX: + case DEBUG_KIND_BOOL: + return true; + case DEBUG_KIND_INT: + return t1->u.kint == t2->u.kint; + } + + /* We have to avoid an infinite recursion. We do this by keeping a + list of types which we are comparing. We just keep the list on + the stack. If we encounter a pair of types we are currently + comparing, we just assume that they are equal. */ + for (l = info->compare_list; l != NULL; l = l->next) + { + if (l->t1 == t1 && l->t2 == t2) + return true; + } + + top.t1 = t1; + top.t2 = t2; + top.next = info->compare_list; + info->compare_list = ⊤ + + switch (t1->kind) + { + default: + abort (); + ret = false; + break; + + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + if (t1->u.kclass == NULL) + ret = t2->u.kclass == NULL; + else if (t2->u.kclass == NULL) + ret = false; + else if (t1->u.kclass->id > info->base_id + && t1->u.kclass->id == t2->u.kclass->id) + ret = true; + else + ret = debug_class_type_samep (info, t1, t2); + break; + + case DEBUG_KIND_ENUM: + if (t1->u.kenum == NULL) + ret = t2->u.kenum == NULL; + else if (t2->u.kenum == NULL) + ret = false; + else + { + const char **pn1, **pn2; + bfd_signed_vma *pv1, *pv2; + + pn1 = t1->u.kenum->names; + pn2 = t2->u.kenum->names; + pv1 = t1->u.kenum->values; + pv2 = t2->u.kenum->values; + while (*pn1 != NULL && *pn2 != NULL) + { + if (**pn1 != **pn2 + || *pv1 != *pv2 + || strcmp (*pn1, *pn2) != 0) + break; + ++pn1; + ++pn2; + ++pv1; + ++pv2; + } + ret = *pn1 == NULL && *pn2 == NULL; + } + break; + + case DEBUG_KIND_POINTER: + ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer); + break; + + case DEBUG_KIND_FUNCTION: + if (t1->u.kfunction->varargs != t2->u.kfunction->varargs + || ! debug_type_samep (info, t1->u.kfunction->return_type, + t2->u.kfunction->return_type) + || ((t1->u.kfunction->arg_types == NULL) + != (t2->u.kfunction->arg_types == NULL))) + ret = false; + else if (t1->u.kfunction->arg_types == NULL) + ret = true; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kfunction->arg_types; + a2 = t2->u.kfunction->arg_types; + while (*a1 != NULL && *a2 != NULL) + if (! debug_type_samep (info, *a1, *a2)) + break; + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_REFERENCE: + ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference); + break; + + case DEBUG_KIND_RANGE: + ret = (t1->u.krange->lower == t2->u.krange->lower + && t1->u.krange->upper == t2->u.krange->upper + && debug_type_samep (info, t1->u.krange->type, + t2->u.krange->type)); + + case DEBUG_KIND_ARRAY: + ret = (t1->u.karray->lower == t2->u.karray->lower + && t1->u.karray->upper == t2->u.karray->upper + && t1->u.karray->stringp == t2->u.karray->stringp + && debug_type_samep (info, t1->u.karray->element_type, + t2->u.karray->element_type)); + break; + + case DEBUG_KIND_SET: + ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp + && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type)); + break; + + case DEBUG_KIND_OFFSET: + ret = (debug_type_samep (info, t1->u.koffset->base_type, + t2->u.koffset->base_type) + && debug_type_samep (info, t1->u.koffset->target_type, + t2->u.koffset->target_type)); + break; + + case DEBUG_KIND_METHOD: + if (t1->u.kmethod->varargs != t2->u.kmethod->varargs + || ! debug_type_samep (info, t1->u.kmethod->return_type, + t2->u.kmethod->return_type) + || ! debug_type_samep (info, t1->u.kmethod->domain_type, + t2->u.kmethod->domain_type) + || ((t1->u.kmethod->arg_types == NULL) + != (t2->u.kmethod->arg_types == NULL))) + ret = false; + else if (t1->u.kmethod->arg_types == NULL) + ret = true; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kmethod->arg_types; + a2 = t2->u.kmethod->arg_types; + while (*a1 != NULL && *a2 != NULL) + if (! debug_type_samep (info, *a1, *a2)) + break; + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_CONST: + ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst); + break; + + case DEBUG_KIND_VOLATILE: + ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile); + break; + + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0 + && debug_type_samep (info, t1->u.knamed->type, + t2->u.knamed->type)); + break; + } + + info->compare_list = top.next; + + return ret; +} + +/* See if two classes are the same. This is a subroutine of + debug_type_samep. */ + +static boolean +debug_class_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_class_type *c1, *c2; + + c1 = t1->u.kclass; + c2 = t2->u.kclass; + + if ((c1->fields == NULL) != (c2->fields == NULL) + || (c1->baseclasses == NULL) != (c2->baseclasses == NULL) + || (c1->methods == NULL) != (c2->methods == NULL) + || (c1->vptrbase == NULL) != (c2->vptrbase == NULL)) + return false; + + if (c1->fields != NULL) + { + struct debug_field **pf1, **pf2; + + for (pf1 = c1->fields, pf2 = c2->fields; + *pf1 != NULL && *pf2 != NULL; + pf1++, pf2++) + { + struct debug_field *f1, *f2; + + f1 = *pf1; + f2 = *pf2; + if (f1->name[0] != f2->name[0] + || f1->visibility != f2->visibility + || f1->static_member != f2->static_member) + return false; + if (f1->static_member) + { + if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0) + return false; + } + else + { + if (f1->u.f.bitpos != f2->u.f.bitpos + || f1->u.f.bitsize != f2->u.f.bitsize) + return false; + } + /* We do the checks which require function calls last. We + don't require that the types of fields have the same + names, since that sometimes fails in the presence of + typedefs and we really don't care. */ + if (strcmp (f1->name, f2->name) != 0 + || ! debug_type_samep (info, + debug_get_real_type ((PTR) info, + f1->type), + debug_get_real_type ((PTR) info, + f2->type))) + return false; + } + if (*pf1 != NULL || *pf2 != NULL) + return false; + } + + if (c1->vptrbase != NULL) + { + if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase)) + return false; + } + + if (c1->baseclasses != NULL) + { + struct debug_baseclass **pb1, **pb2; + + for (pb1 = c1->baseclasses, pb2 = c2->baseclasses; + *pb1 != NULL && *pb2 != NULL; + ++pb1, ++pb2) + { + struct debug_baseclass *b1, *b2; + + b1 = *pb1; + b2 = *pb2; + if (b1->bitpos != b2->bitpos + || b1->virtual != b2->virtual + || b1->visibility != b2->visibility + || ! debug_type_samep (info, b1->type, b2->type)) + return false; + } + if (*pb1 != NULL || *pb2 != NULL) + return false; + } + + if (c1->methods != NULL) + { + struct debug_method **pm1, **pm2; + + for (pm1 = c1->methods, pm2 = c2->methods; + *pm1 != NULL && *pm2 != NULL; + ++pm1, ++pm2) + { + struct debug_method *m1, *m2; + + m1 = *pm1; + m2 = *pm2; + if (m1->name[0] != m2->name[0] + || strcmp (m1->name, m2->name) != 0 + || (m1->variants == NULL) != (m2->variants == NULL)) + return false; + if (m1->variants == NULL) + { + struct debug_method_variant **pv1, **pv2; + + for (pv1 = m1->variants, pv2 = m2->variants; + *pv1 != NULL && *pv2 != NULL; + ++pv1, ++pv2) + { + struct debug_method_variant *v1, *v2; + + v1 = *pv1; + v2 = *pv2; + if (v1->physname[0] != v2->physname[0] + || v1->visibility != v2->visibility + || v1->constp != v2->constp + || v1->volatilep != v2->volatilep + || v1->voffset != v2->voffset + || (v1->context == NULL) != (v2->context == NULL) + || strcmp (v1->physname, v2->physname) != 0 + || ! debug_type_samep (info, v1->type, v2->type)) + return false; + if (v1->context != NULL) + { + if (! debug_type_samep (info, v1->context, + v2->context)) + return false; + } + } + if (*pv1 != NULL || *pv2 != NULL) + return false; + } + } + if (*pm1 != NULL || *pm2 != NULL) + return false; + } + + return true; +} diff --git a/pstack/debug.h b/pstack/debug.h new file mode 100644 index 00000000000..1b890b234f1 --- /dev/null +++ b/pstack/debug.h @@ -0,0 +1,798 @@ +/* debug.h -- Describe generic debugging information. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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 DEBUG_H +#define DEBUG_H + +/* This header file describes a generic debugging information format. + We may eventually have readers which convert different formats into + this generic format, and writers which write it out. The initial + impetus for this was writing a convertor from stabs to HP IEEE-695 + debugging format. */ + +/* Different kinds of types. */ + +enum debug_type_kind +{ + /* Not used. */ + DEBUG_KIND_ILLEGAL, + /* Indirect via a pointer. */ + DEBUG_KIND_INDIRECT, + /* Void. */ + DEBUG_KIND_VOID, + /* Integer. */ + DEBUG_KIND_INT, + /* Floating point. */ + DEBUG_KIND_FLOAT, + /* Complex. */ + DEBUG_KIND_COMPLEX, + /* Boolean. */ + DEBUG_KIND_BOOL, + /* Struct. */ + DEBUG_KIND_STRUCT, + /* Union. */ + DEBUG_KIND_UNION, + /* Class. */ + DEBUG_KIND_CLASS, + /* Union class (can this really happen?). */ + DEBUG_KIND_UNION_CLASS, + /* Enumeration type. */ + DEBUG_KIND_ENUM, + /* Pointer. */ + DEBUG_KIND_POINTER, + /* Function. */ + DEBUG_KIND_FUNCTION, + /* Reference. */ + DEBUG_KIND_REFERENCE, + /* Range. */ + DEBUG_KIND_RANGE, + /* Array. */ + DEBUG_KIND_ARRAY, + /* Set. */ + DEBUG_KIND_SET, + /* Based pointer. */ + DEBUG_KIND_OFFSET, + /* Method. */ + DEBUG_KIND_METHOD, + /* Const qualified type. */ + DEBUG_KIND_CONST, + /* Volatile qualified type. */ + DEBUG_KIND_VOLATILE, + /* Named type. */ + DEBUG_KIND_NAMED, + /* Tagged type. */ + DEBUG_KIND_TAGGED +}; + +/* Different kinds of variables. */ + +enum debug_var_kind +{ + /* Not used. */ + DEBUG_VAR_ILLEGAL, + /* A global variable. */ + DEBUG_GLOBAL, + /* A static variable. */ + DEBUG_STATIC, + /* A local static variable. */ + DEBUG_LOCAL_STATIC, + /* A local variable. */ + DEBUG_LOCAL, + /* A register variable. */ + DEBUG_REGISTER +}; + +/* Different kinds of function parameters. */ + +enum debug_parm_kind +{ + /* Not used. */ + DEBUG_PARM_ILLEGAL, + /* A stack based parameter. */ + DEBUG_PARM_STACK, + /* A register parameter. */ + DEBUG_PARM_REG, + /* A stack based reference parameter. */ + DEBUG_PARM_REFERENCE, + /* A register reference parameter. */ + DEBUG_PARM_REF_REG +}; + +/* Different kinds of visibility. */ + +enum debug_visibility +{ + /* A public field (e.g., a field in a C struct). */ + DEBUG_VISIBILITY_PUBLIC, + /* A protected field. */ + DEBUG_VISIBILITY_PROTECTED, + /* A private field. */ + DEBUG_VISIBILITY_PRIVATE, + /* A field which should be ignored. */ + DEBUG_VISIBILITY_IGNORE +}; + +/* A type. */ + +typedef struct debug_type *debug_type; + +#define DEBUG_TYPE_NULL ((debug_type) NULL) + +/* A field in a struct or union. */ + +typedef struct debug_field *debug_field; + +#define DEBUG_FIELD_NULL ((debug_field) NULL) + +/* A base class for an object. */ + +typedef struct debug_baseclass *debug_baseclass; + +#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL) + +/* A method of an object. */ + +typedef struct debug_method *debug_method; + +#define DEBUG_METHOD_NULL ((debug_method) NULL) + +/* The arguments to a method function of an object. These indicate + which method to run. */ + +typedef struct debug_method_variant *debug_method_variant; + +#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL) + +/* This structure is passed to debug_write. It holds function + pointers that debug_write will call based on the accumulated + debugging information. */ + +struct debug_write_fns +{ + /* This is called at the start of each new compilation unit with the + name of the main file in the new unit. */ + boolean (*start_compilation_unit) PARAMS ((PTR, const char *)); + + /* This is called at the start of each source file within a + compilation unit, before outputting any global information for + that file. The argument is the name of the file. */ + boolean (*start_source) PARAMS ((PTR, const char *)); + + /* Each writer must keep a stack of types. */ + + /* Push an empty type onto the type stack. This type can appear if + there is a reference to a type which is never defined. */ + boolean (*empty_type) PARAMS ((PTR)); + + /* Push a void type onto the type stack. */ + boolean (*void_type) PARAMS ((PTR)); + + /* Push an integer type onto the type stack, given the size and + whether it is unsigned. */ + boolean (*int_type) PARAMS ((PTR, unsigned int, boolean)); + + /* Push a floating type onto the type stack, given the size. */ + boolean (*float_type) PARAMS ((PTR, unsigned int)); + + /* Push a complex type onto the type stack, given the size. */ + boolean (*complex_type) PARAMS ((PTR, unsigned int)); + + /* Push a boolean type onto the type stack, given the size. */ + boolean (*bool_type) PARAMS ((PTR, unsigned int)); + + /* Push an enum type onto the type stack, given the tag, a NULL + terminated array of names and the associated values. If there is + no tag, the tag argument will be NULL. If this is an undefined + enum, the names and values arguments will be NULL. */ + boolean (*enum_type) PARAMS ((PTR, const char *, const char **, + bfd_signed_vma *)); + + /* Pop the top type on the type stack, and push a pointer to that + type onto the type stack. */ + boolean (*pointer_type) PARAMS ((PTR)); + + /* Push a function type onto the type stack. The second argument + indicates the number of argument types that have been pushed onto + the stack. If the number of argument types is passed as -1, then + the argument types of the function are unknown, and no types have + been pushed onto the stack. The third argument is true if the + function takes a variable number of arguments. The return type + of the function is pushed onto the type stack below the argument + types, if any. */ + boolean (*function_type) PARAMS ((PTR, int, boolean)); + + /* Pop the top type on the type stack, and push a reference to that + type onto the type stack. */ + boolean (*reference_type) PARAMS ((PTR)); + + /* Pop the top type on the type stack, and push a range of that type + with the given lower and upper bounds onto the type stack. */ + boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); + + /* Push an array type onto the type stack. The top type on the type + stack is the range, and the next type on the type stack is the + element type. These should be popped before the array type is + pushed. The arguments are the lower bound, the upper bound, and + whether the array is a string. */ + boolean (*array_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, + boolean)); + + /* Pop the top type on the type stack, and push a set of that type + onto the type stack. The argument indicates whether this set is + a bitstring. */ + boolean (*set_type) PARAMS ((PTR, boolean)); + + /* Push an offset type onto the type stack. The top type on the + type stack is the target type, and the next type on the type + stack is the base type. These should be popped before the offset + type is pushed. */ + boolean (*offset_type) PARAMS ((PTR)); + + /* Push a method type onto the type stack. If the second argument + is true, the top type on the stack is the class to which the + method belongs; otherwise, the class must be determined by the + class to which the method is attached. The third argument is the + number of argument types; these are pushed onto the type stack in + reverse order (the first type popped is the last argument to the + method). A value of -1 for the third argument means that no + argument information is available. The fourth argument is true + if the function takes a variable number of arguments. The next + type on the type stack below the domain and the argument types is + the return type of the method. All these types must be popped, + and then the method type must be pushed. */ + boolean (*method_type) PARAMS ((PTR, boolean, int, boolean)); + + /* Pop the top type off the type stack, and push a const qualified + version of that type onto the type stack. */ + boolean (*const_type) PARAMS ((PTR)); + + /* Pop the top type off the type stack, and push a volatile + qualified version of that type onto the type stack. */ + boolean (*volatile_type) PARAMS ((PTR)); + + /* Start building a struct. This is followed by calls to the + struct_field function, and finished by a call to the + end_struct_type function. The second argument is the tag; this + will be NULL if there isn't one. If the second argument is NULL, + the third argument is a constant identifying this struct for use + with tag_type. The fourth argument is true for a struct, false + for a union. The fifth argument is the size. If this is an + undefined struct or union, the size will be 0 and struct_field + will not be called before end_struct_type is called. */ + boolean (*start_struct_type) PARAMS ((PTR, const char *, unsigned int, + boolean, unsigned int)); + + /* Add a field to the struct type currently being built. The type + of the field should be popped off the type stack. The arguments + are the name, the bit position, the bit size (may be zero if the + field is not packed), and the visibility. */ + boolean (*struct_field) PARAMS ((PTR, const char *, bfd_vma, bfd_vma, + enum debug_visibility)); + + /* Finish building a struct, and push it onto the type stack. */ + boolean (*end_struct_type) PARAMS ((PTR)); + + /* Start building a class. This is followed by calls to several + functions: struct_field, class_static_member, class_baseclass, + class_start_method, class_method_variant, + class_static_method_variant, and class_end_method. The class is + finished by a call to end_class_type. The first five arguments + are the same as for start_struct_type. The sixth argument is + true if there is a virtual function table; if there is, the + seventh argument is true if the virtual function table can be + found in the type itself, and is false if the type of the object + holding the virtual function table should be popped from the type + stack. */ + boolean (*start_class_type) PARAMS ((PTR, const char *, unsigned int, + boolean, unsigned int, boolean, + boolean)); + + /* Add a static member to the class currently being built. The + arguments are the field name, the physical name, and the + visibility. The type must be popped off the type stack. */ + boolean (*class_static_member) PARAMS ((PTR, const char *, const char *, + enum debug_visibility)); + + /* Add a baseclass to the class currently being built. The type of + the baseclass must be popped off the type stack. The arguments + are the bit position, whether the class is virtual, and the + visibility. */ + boolean (*class_baseclass) PARAMS ((PTR, bfd_vma, boolean, + enum debug_visibility)); + + /* Start adding a method to the class currently being built. This + is followed by calls to class_method_variant and + class_static_method_variant to describe different variants of the + method which take different arguments. The method is finished + with a call to class_end_method. The argument is the method + name. */ + boolean (*class_start_method) PARAMS ((PTR, const char *)); + + /* Describe a variant to the class method currently being built. + The type of the variant must be popped off the type stack. The + second argument is the physical name of the function. The + following arguments are the visibility, whether the variant is + const, whether the variant is volatile, the offset in the virtual + function table, and whether the context is on the type stack + (below the variant type). */ + boolean (*class_method_variant) PARAMS ((PTR, const char *, + enum debug_visibility, + boolean, boolean, + bfd_vma, boolean)); + + /* Describe a static variant to the class method currently being + built. The arguments are the same as for class_method_variant, + except that the last two arguments are omitted. The type of the + variant must be popped off the type stack. */ + boolean (*class_static_method_variant) PARAMS ((PTR, const char *, + enum debug_visibility, + boolean, boolean)); + + /* Finish describing a class method. */ + boolean (*class_end_method) PARAMS ((PTR)); + + /* Finish describing a class, and push it onto the type stack. */ + boolean (*end_class_type) PARAMS ((PTR)); + + /* Push a type on the stack which was given a name by an earlier + call to typdef. */ + boolean (*typedef_type) PARAMS ((PTR, const char *)); + + /* Push a tagged type on the stack which was defined earlier. If + the second argument is not NULL, the type was defined by a call + to tag. If the second argument is NULL, the type was defined by + a call to start_struct_type or start_class_type with a tag of + NULL and the number of the third argument. Either way, the + fourth argument is the tag kind. Note that this may be called + for a struct (class) being defined, in between the call to + start_struct_type (start_class_type) and the call to + end_struct_type (end_class_type). */ + boolean (*tag_type) PARAMS ((PTR, const char *, unsigned int, + enum debug_type_kind)); + + /* Pop the type stack, and typedef it to the given name. */ + boolean (*typdef) PARAMS ((PTR, const char *)); + + /* Pop the type stack, and declare it as a tagged struct or union or + enum or whatever. The tag passed down here is redundant, since + was also passed when enum_type, start_struct_type, or + start_class_type was called. */ + boolean (*tag) PARAMS ((PTR, const char *)); + + /* This is called to record a named integer constant. */ + boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma)); + + /* This is called to record a named floating point constant. */ + boolean (*float_constant) PARAMS ((PTR, const char *, double)); + + /* This is called to record a typed integer constant. The type is + popped off the type stack. */ + boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma)); + + /* This is called to record a variable. The type is popped off the + type stack. */ + boolean (*variable) PARAMS ((PTR, const char *, enum debug_var_kind, + bfd_vma)); + + /* Start writing out a function. The return type must be popped off + the stack. The boolean is true if the function is global. This + is followed by calls to function_parameter, followed by block + information. */ + boolean (*start_function) PARAMS ((PTR, const char *, boolean)); + + /* Record a function parameter for the current function. The type + must be popped off the stack. */ + boolean (*function_parameter) PARAMS ((PTR, const char *, + enum debug_parm_kind, bfd_vma)); + + /* Start writing out a block. There is at least one top level block + per function. Blocks may be nested. The argument is the + starting address of the block. */ + boolean (*start_block) PARAMS ((PTR, bfd_vma)); + + /* Finish writing out a block. The argument is the ending address + of the block. */ + boolean (*end_block) PARAMS ((PTR, bfd_vma)); + + /* Finish writing out a function. */ + boolean (*end_function) PARAMS ((PTR)); + + /* Record line number information for the current compilation unit. */ + boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma)); +}; + +/* Exported functions. */ + +/* The first argument to most of these functions is a handle. This + handle is returned by the debug_init function. The purpose of the + handle is to permit the debugging routines to not use static + variables, and hence to be reentrant. This would be useful for a + program which wanted to handle two executables simultaneously. */ + +/* Return a debugging handle. */ + +extern PTR debug_init PARAMS ((void)); + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +extern boolean debug_set_filename PARAMS ((PTR, const char *)); + +/* Change source files to the given file name. This is used for + include files in a single compilation unit. */ + +extern boolean debug_start_source PARAMS ((PTR, const char *)); + +/* Record a function definition. This implicitly starts a function + block. The debug_type argument is the type of the return value. + The boolean indicates whether the function is globally visible. + The bfd_vma is the address of the start of the function. Currently + the parameter types are specified by calls to + debug_record_parameter. */ + +extern boolean debug_record_function + PARAMS ((PTR, const char *, debug_type, boolean, bfd_vma)); + +/* Record a parameter for the current function. */ + +extern boolean debug_record_parameter + PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma)); + +/* End a function definition. The argument is the address where the + function ends. */ + +extern boolean debug_end_function PARAMS ((PTR, bfd_vma)); + +/* Start a block in a function. All local information will be + recorded in this block, until the matching call to debug_end_block. + debug_start_block and debug_end_block may be nested. The argument + is the address at which this block starts. */ + +extern boolean debug_start_block PARAMS ((PTR, bfd_vma)); + +/* Finish a block in a function. This matches the call to + debug_start_block. The argument is the address at which this block + ends. */ + +extern boolean debug_end_block PARAMS ((PTR, bfd_vma)); + +/* Associate a line number in the current source file with a given + address. */ + +extern boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma)); + +/* Start a named common block. This is a block of variables that may + move in memory. */ + +extern boolean debug_start_common_block PARAMS ((PTR, const char *)); + +/* End a named common block. */ + +extern boolean debug_end_common_block PARAMS ((PTR, const char *)); + +/* Record a named integer constant. */ + +extern boolean debug_record_int_const PARAMS ((PTR, const char *, bfd_vma)); + +/* Record a named floating point constant. */ + +extern boolean debug_record_float_const PARAMS ((PTR, const char *, double)); + +/* Record a typed constant with an integral value. */ + +extern boolean debug_record_typed_const + PARAMS ((PTR, const char *, debug_type, bfd_vma)); + +/* Record a label. */ + +extern boolean debug_record_label + PARAMS ((PTR, const char *, debug_type, bfd_vma)); + +/* Record a variable. */ + +extern boolean debug_record_variable + PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma)); + +/* Make an indirect type. The first argument is a pointer to the + location where the real type will be placed. The second argument + is the type tag, if there is one; this may be NULL; the only + purpose of this argument is so that debug_get_type_name can return + something useful. This function may be used when a type is + referenced before it is defined. */ + +extern debug_type debug_make_indirect_type + PARAMS ((PTR, debug_type *, const char *)); + +/* Make a void type. */ + +extern debug_type debug_make_void_type PARAMS ((PTR)); + +/* Make an integer type of a given size. The boolean argument is true + if the integer is unsigned. */ + +extern debug_type debug_make_int_type PARAMS ((PTR, unsigned int, boolean)); + +/* Make a floating point type of a given size. FIXME: On some + platforms, like an Alpha, you probably need to be able to specify + the format. */ + +extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int)); + +/* Make a boolean type of a given size. */ + +extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int)); + +/* Make a complex type of a given size. */ + +extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int)); + +/* Make a structure type. The second argument is true for a struct, + false for a union. The third argument is the size of the struct. + The fourth argument is a NULL terminated array of fields. */ + +extern debug_type debug_make_struct_type + PARAMS ((PTR, boolean, bfd_vma, debug_field *)); + +/* Make an object type. The first three arguments after the handle + are the same as for debug_make_struct_type. The next arguments are + a NULL terminated array of base classes, a NULL terminated array of + methods, the type of the object holding the virtual function table + if it is not this object, and a boolean which is true if this + object has its own virtual function table. */ + +extern debug_type debug_make_object_type + PARAMS ((PTR, boolean, bfd_vma, debug_field *, debug_baseclass *, + debug_method *, debug_type, boolean)); + +/* Make an enumeration type. The arguments are a null terminated + array of strings, and an array of corresponding values. */ + +extern debug_type debug_make_enum_type + PARAMS ((PTR, const char **, bfd_signed_vma *)); + +/* Make a pointer to a given type. */ + +extern debug_type debug_make_pointer_type + PARAMS ((PTR, debug_type)); + +/* Make a function type. The second argument is the return type. The + third argument is a NULL terminated array of argument types. The + fourth argument is true if the function takes a variable number of + arguments. If the third argument is NULL, then the argument types + are unknown. */ + +extern debug_type debug_make_function_type + PARAMS ((PTR, debug_type, debug_type *, boolean)); + +/* Make a reference to a given type. */ + +extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type)); + +/* Make a range of a given type from a lower to an upper bound. */ + +extern debug_type debug_make_range_type + PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma)); + +/* Make an array type. The second argument is the type of an element + of the array. The third argument is the type of a range of the + array. The fourth and fifth argument are the lower and upper + bounds, respectively (if the bounds are not known, lower should be + 0 and upper should be -1). The sixth argument is true if this + array is actually a string, as in C. */ + +extern debug_type debug_make_array_type + PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma, + boolean)); + +/* Make a set of a given type. For example, a Pascal set type. The + boolean argument is true if this set is actually a bitstring, as in + CHILL. */ + +extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, boolean)); + +/* Make a type for a pointer which is relative to an object. The + second argument is the type of the object to which the pointer is + relative. The third argument is the type that the pointer points + to. */ + +extern debug_type debug_make_offset_type + PARAMS ((PTR, debug_type, debug_type)); + +/* Make a type for a method function. The second argument is the + return type. The third argument is the domain. The fourth + argument is a NULL terminated array of argument types. The fifth + argument is true if the function takes a variable number of + arguments, in which case the array of argument types indicates the + types of the first arguments. The domain and the argument array + may be NULL, in which case this is a stub method and that + information is not available. Stabs debugging uses this, and gets + the argument types from the mangled name. */ + +extern debug_type debug_make_method_type + PARAMS ((PTR, debug_type, debug_type, debug_type *, boolean)); + +/* Make a const qualified version of a given type. */ + +extern debug_type debug_make_const_type PARAMS ((PTR, debug_type)); + +/* Make a volatile qualified version of a given type. */ + +extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type)); + +/* Make an undefined tagged type. For example, a struct which has + been mentioned, but not defined. */ + +extern debug_type debug_make_undefined_tagged_type + PARAMS ((PTR, const char *, enum debug_type_kind)); + +/* Make a base class for an object. The second argument is the base + class type. The third argument is the bit position of this base + class in the object. The fourth argument is whether this is a + virtual class. The fifth argument is the visibility of the base + class. */ + +extern debug_baseclass debug_make_baseclass + PARAMS ((PTR, debug_type, bfd_vma, boolean, enum debug_visibility)); + +/* Make a field for a struct. The second argument is the name. The + third argument is the type of the field. The fourth argument is + the bit position of the field. The fifth argument is the size of + the field (it may be zero). The sixth argument is the visibility + of the field. */ + +extern debug_field debug_make_field + PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma, + enum debug_visibility)); + +/* Make a static member of an object. The second argument is the + name. The third argument is the type of the member. The fourth + argument is the physical name of the member (i.e., the name as a + global variable). The fifth argument is the visibility of the + member. */ + +extern debug_field debug_make_static_member + PARAMS ((PTR, const char *, debug_type, const char *, + enum debug_visibility)); + +/* Make a method. The second argument is the name, and the third + argument is a NULL terminated array of method variants. Each + method variant is a method with this name but with different + argument types. */ + +extern debug_method debug_make_method + PARAMS ((PTR, const char *, debug_method_variant *)); + +/* Make a method variant. The second argument is the physical name of + the function. The third argument is the type of the function, + probably constructed by debug_make_method_type. The fourth + argument is the visibility. The fifth argument is whether this is + a const function. The sixth argument is whether this is a volatile + function. The seventh argument is the index in the virtual + function table, if any. The eighth argument is the virtual + function context. */ + +extern debug_method_variant debug_make_method_variant + PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean, + boolean, bfd_vma, debug_type)); + +/* Make a static method argument. The arguments are the same as for + debug_make_method_variant, except that the last two are omitted + since a static method can not also be virtual. */ + +extern debug_method_variant debug_make_static_method_variant + PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean, + boolean)); + +/* Name a type. This returns a new type with an attached name. */ + +extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type)); + +/* Give a tag to a type, such as a struct or union. This returns a + new type with an attached tag. */ + +extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type)); + +/* Record the size of a given type. */ + +extern boolean debug_record_type_size PARAMS ((PTR, debug_type, unsigned int)); + +/* Find a named type. */ + +extern debug_type debug_find_named_type PARAMS ((PTR, const char *)); + +/* Find a tagged type. */ + +extern debug_type debug_find_tagged_type + PARAMS ((PTR, const char *, enum debug_type_kind)); + +/* Get the kind of a type. */ + +extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type)); + +/* Get the name of a type. */ + +extern const char *debug_get_type_name PARAMS ((PTR, debug_type)); + +/* Get the size of a type. */ + +extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type)); + +/* Get the return type of a function or method type. */ + +extern debug_type debug_get_return_type PARAMS ((PTR, debug_type)); + +/* Get the NULL terminated array of parameter types for a function or + method type (actually, parameter types are not currently stored for + function types). This may be used to determine whether a method + type is a stub method or not. The last argument points to a + boolean which is set to true if the function takes a variable + number of arguments. */ + +extern const debug_type *debug_get_parameter_types PARAMS ((PTR, + debug_type, + boolean *)); + +/* Get the target type of a pointer or reference or const or volatile + type. */ + +extern debug_type debug_get_target_type PARAMS ((PTR, debug_type)); + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type)); + +/* Get the type of a field. */ + +extern debug_type debug_get_field_type PARAMS ((PTR, debug_field)); + +/* Get the name of a field. */ + +extern const char *debug_get_field_name PARAMS ((PTR, debug_field)); + +/* Get the bit position of a field within the containing structure. + If the field is a static member, this will return (bfd_vma) -1. */ + +extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field)); + +/* Get the bit size of a field. If the field is a static member, this + will return (bfd_vma) -1. */ + +extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field)); + +/* Get the visibility of a field. */ + +extern enum debug_visibility debug_get_field_visibility + PARAMS ((PTR, debug_field)); + +/* Get the physical name of a field, if it is a static member. If the + field is not a static member, this will return NULL. */ + +extern const char *debug_get_field_physname PARAMS ((PTR, debug_field)); + +/* Write out the recorded debugging information. This takes a set of + function pointers which are called to do the actual writing. The + first PTR is the debugging handle. The second PTR is a handle + which is passed to the functions. */ + +extern boolean debug_write PARAMS ((PTR, const struct debug_write_fns *, PTR)); + +#endif /* DEBUG_H */ diff --git a/pstack/demangle.h b/pstack/demangle.h new file mode 100644 index 00000000000..00f6a0c3bc0 --- /dev/null +++ b/pstack/demangle.h @@ -0,0 +1,90 @@ +/* Defs for interface to demanglers. + Copyright 1992, 1995, 1996 Free Software Foundation, Inc. + + 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, 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. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#ifdef IN_GCC +#include "gansidecl.h" +#define PARAMS(ARGS) PROTO(ARGS) +#else /* ! IN_GCC */ +#include <ansidecl.h> +#endif /* IN_GCC */ + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM) + +extern char * +cplus_demangle PARAMS ((const char *mangled, int options)); + +extern int +cplus_demangle_opname PARAMS ((const char *opname, char *result, int options)); + +extern const char * +cplus_mangle_opname PARAMS ((const char *opname, int options)); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling PARAMS ((int ch)); + +#endif /* DEMANGLE_H */ diff --git a/pstack/filemode.c b/pstack/filemode.c new file mode 100644 index 00000000000..58b52ba7489 --- /dev/null +++ b/pstack/filemode.c @@ -0,0 +1,266 @@ +/* filemode.c -- make a string describing file modes + Copyright (C) 1985, 90, 91, 94, 95, 1997 Free Software Foundation, Inc. + + 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, 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 "bfd.h" +#include "bucomm.h" + +static char ftypelet PARAMS ((unsigned long)); +static void setst PARAMS ((unsigned long, char *)); + +/* filemodestring - fill in string STR with an ls-style ASCII + representation of the st_mode field of file stats block STATP. + 10 characters are stored in STR; no terminating null is added. + The characters stored in STR are: + + 0 File type. 'd' for directory, 'c' for character + special, 'b' for block special, 'm' for multiplex, + 'l' for symbolic link, 's' for socket, 'p' for fifo, + '-' for any other file type + + 1 'r' if the owner may read, '-' otherwise. + + 2 'w' if the owner may write, '-' otherwise. + + 3 'x' if the owner may execute, 's' if the file is + set-user-id, '-' otherwise. + 'S' if the file is set-user-id, but the execute + bit isn't set. + + 4 'r' if group members may read, '-' otherwise. + + 5 'w' if group members may write, '-' otherwise. + + 6 'x' if group members may execute, 's' if the file is + set-group-id, '-' otherwise. + 'S' if it is set-group-id but not executable. + + 7 'r' if any user may read, '-' otherwise. + + 8 'w' if any user may write, '-' otherwise. + + 9 'x' if any user may execute, 't' if the file is "sticky" + (will be retained in swap space after execution), '-' + otherwise. + 'T' if the file is sticky but not executable. */ + +#if 0 + +/* This is not used; only mode_string is used. */ + +void +filemodestring (statp, str) + struct stat *statp; + char *str; +{ + mode_string ((unsigned long) statp->st_mode, str); +} + +#endif + +/* Get definitions for the file permission bits. */ + +#ifndef S_IRWXU +#define S_IRWXU 0700 +#endif +#ifndef S_IRUSR +#define S_IRUSR 0400 +#endif +#ifndef S_IWUSR +#define S_IWUSR 0200 +#endif +#ifndef S_IXUSR +#define S_IXUSR 0100 +#endif + +#ifndef S_IRWXG +#define S_IRWXG 0070 +#endif +#ifndef S_IRGRP +#define S_IRGRP 0040 +#endif +#ifndef S_IWGRP +#define S_IWGRP 0020 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 +#endif + +#ifndef S_IRWXO +#define S_IRWXO 0007 +#endif +#ifndef S_IROTH +#define S_IROTH 0004 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0002 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 +#endif + +/* Like filemodestring, but only the relevant part of the `struct stat' + is given as an argument. */ + +void +mode_string (mode, str) + unsigned long mode; + char *str; +{ + str[0] = ftypelet ((unsigned long) mode); + str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-'; + str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-'; + str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-'; + str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-'; + str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-'; + str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-'; + str[7] = (mode & S_IROTH) != 0 ? 'r' : '-'; + str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-'; + str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-'; + setst ((unsigned long) mode, str); +} + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for any other file type. */ + +#ifndef S_ISDIR +#ifdef S_IFDIR +#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) +#else /* ! defined (S_IFDIR) */ +#define S_ISDIR(i) (((i) & 0170000) == 040000) +#endif /* ! defined (S_IFDIR) */ +#endif /* ! defined (S_ISDIR) */ + +#ifndef S_ISBLK +#ifdef S_IFBLK +#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK) +#else /* ! defined (S_IFBLK) */ +#define S_ISBLK(i) 0 +#endif /* ! defined (S_IFBLK) */ +#endif /* ! defined (S_ISBLK) */ + +#ifndef S_ISCHR +#ifdef S_IFCHR +#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR) +#else /* ! defined (S_IFCHR) */ +#define S_ISCHR(i) 0 +#endif /* ! defined (S_IFCHR) */ +#endif /* ! defined (S_ISCHR) */ + +#ifndef S_ISFIFO +#ifdef S_IFIFO +#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO) +#else /* ! defined (S_IFIFO) */ +#define S_ISFIFO(i) 0 +#endif /* ! defined (S_IFIFO) */ +#endif /* ! defined (S_ISFIFO) */ + +#ifndef S_ISSOCK +#ifdef S_IFSOCK +#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK) +#else /* ! defined (S_IFSOCK) */ +#define S_ISSOCK(i) 0 +#endif /* ! defined (S_IFSOCK) */ +#endif /* ! defined (S_ISSOCK) */ + +#ifndef S_ISLNK +#ifdef S_IFLNK +#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK) +#else /* ! defined (S_IFLNK) */ +#define S_ISLNK(i) 0 +#endif /* ! defined (S_IFLNK) */ +#endif /* ! defined (S_ISLNK) */ + +static char +ftypelet (bits) + unsigned long bits; +{ + if (S_ISDIR (bits)) + return 'd'; + if (S_ISLNK (bits)) + return 'l'; + if (S_ISBLK (bits)) + return 'b'; + if (S_ISCHR (bits)) + return 'c'; + if (S_ISSOCK (bits)) + return 's'; + if (S_ISFIFO (bits)) + return 'p'; + +#ifdef S_IFMT +#ifdef S_IFMPC + if ((bits & S_IFMT) == S_IFMPC + || (bits & S_IFMT) == S_IFMPB) + return 'm'; +#endif +#ifdef S_IFNWK + if ((bits & S_IFMT) == S_IFNWK) + return 'n'; +#endif +#endif + + return '-'; +} + +/* Set the 's' and 't' flags in file attributes string CHARS, + according to the file mode BITS. */ + +static void +setst (bits, chars) + unsigned long bits; + char *chars; +{ +#ifdef S_ISUID + if (bits & S_ISUID) + { + if (chars[3] != 'x') + /* Set-uid, but not executable by owner. */ + chars[3] = 'S'; + else + chars[3] = 's'; + } +#endif +#ifdef S_ISGID + if (bits & S_ISGID) + { + if (chars[6] != 'x') + /* Set-gid, but not executable by group. */ + chars[6] = 'S'; + else + chars[6] = 's'; + } +#endif +#ifdef S_ISVTX + if (bits & S_ISVTX) + { + if (chars[9] != 'x') + /* Sticky, but not executable by others. */ + chars[9] = 'T'; + else + chars[9] = 't'; + } +#endif +} diff --git a/pstack/ieee.c b/pstack/ieee.c new file mode 100644 index 00000000000..4b6ce69ebc6 --- /dev/null +++ b/pstack/ieee.c @@ -0,0 +1,7602 @@ +/* ieee.c -- Read and write IEEE-695 debugging information. + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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. */ + +/* This file reads and writes IEEE-695 debugging information. */ + +#include <stdio.h> +#include <assert.h> + +#include <bfd.h> +#include "ieee.h" +#include "bucomm.h" +#include <libiberty.h> +#include "debug.h" +#include "budbg.h" + +/* This structure holds an entry on the block stack. */ + +struct ieee_block +{ + /* The kind of block. */ + int kind; + /* The source file name, for a BB5 block. */ + const char *filename; + /* The index of the function type, for a BB4 or BB6 block. */ + unsigned int fnindx; + /* True if this function is being skipped. */ + boolean skip; +}; + +/* This structure is the block stack. */ + +#define BLOCKSTACK_SIZE (16) + +struct ieee_blockstack +{ + /* The stack pointer. */ + struct ieee_block *bsp; + /* The stack. */ + struct ieee_block stack[BLOCKSTACK_SIZE]; +}; + +/* This structure holds information for a variable. */ + +struct ieee_var +{ + /* Start of name. */ + const char *name; + /* Length of name. */ + unsigned long namlen; + /* Type. */ + debug_type type; + /* Slot if we make an indirect type. */ + debug_type *pslot; + /* Kind of variable or function. */ + enum + { + IEEE_UNKNOWN, + IEEE_EXTERNAL, + IEEE_GLOBAL, + IEEE_STATIC, + IEEE_LOCAL, + IEEE_FUNCTION + } kind; +}; + +/* This structure holds all the variables. */ + +struct ieee_vars +{ + /* Number of slots allocated. */ + unsigned int alloc; + /* Variables. */ + struct ieee_var *vars; +}; + +/* This structure holds information for a type. We need this because + we don't want to represent bitfields as real types. */ + +struct ieee_type +{ + /* Type. */ + debug_type type; + /* Slot if this is type is referenced before it is defined. */ + debug_type *pslot; + /* Slots for arguments if we make indirect types for them. */ + debug_type *arg_slots; + /* If this is a bitfield, this is the size in bits. If this is not + a bitfield, this is zero. */ + unsigned long bitsize; +}; + +/* This structure holds all the type information. */ + +struct ieee_types +{ + /* Number of slots allocated. */ + unsigned int alloc; + /* Types. */ + struct ieee_type *types; + /* Builtin types. */ +#define BUILTIN_TYPE_COUNT (60) + debug_type builtins[BUILTIN_TYPE_COUNT]; +}; + +/* This structure holds a linked last of structs with their tag names, + so that we can convert them to C++ classes if necessary. */ + +struct ieee_tag +{ + /* Next tag. */ + struct ieee_tag *next; + /* This tag name. */ + const char *name; + /* The type of the tag. */ + debug_type type; + /* The tagged type is an indirect type pointing at this slot. */ + debug_type slot; + /* This is an array of slots used when a field type is converted + into a indirect type, in case it needs to be later converted into + a reference type. */ + debug_type *fslots; +}; + +/* This structure holds the information we pass around to the parsing + functions. */ + +struct ieee_info +{ + /* The debugging handle. */ + PTR dhandle; + /* The BFD. */ + bfd *abfd; + /* The start of the bytes to be parsed. */ + const bfd_byte *bytes; + /* The end of the bytes to be parsed. */ + const bfd_byte *pend; + /* The block stack. */ + struct ieee_blockstack blockstack; + /* Whether we have seen a BB1 or BB2. */ + boolean saw_filename; + /* The variables. */ + struct ieee_vars vars; + /* The global variables, after a global typedef block. */ + struct ieee_vars *global_vars; + /* The types. */ + struct ieee_types types; + /* The global types, after a global typedef block. */ + struct ieee_types *global_types; + /* The list of tagged structs. */ + struct ieee_tag *tags; +}; + +/* Basic builtin types, not including the pointers. */ + +enum builtin_types +{ + builtin_unknown = 0, + builtin_void = 1, + builtin_signed_char = 2, + builtin_unsigned_char = 3, + builtin_signed_short_int = 4, + builtin_unsigned_short_int = 5, + builtin_signed_long = 6, + builtin_unsigned_long = 7, + builtin_signed_long_long = 8, + builtin_unsigned_long_long = 9, + builtin_float = 10, + builtin_double = 11, + builtin_long_double = 12, + builtin_long_long_double = 13, + builtin_quoted_string = 14, + builtin_instruction_address = 15, + builtin_int = 16, + builtin_unsigned = 17, + builtin_unsigned_int = 18, + builtin_char = 19, + builtin_long = 20, + builtin_short = 21, + builtin_unsigned_short = 22, + builtin_short_int = 23, + builtin_signed_short = 24, + builtin_bcd_float = 25 +}; + +/* These are the values found in the derivation flags of a 'b' + component record of a 'T' type extension record in a C++ pmisc + record. These are bitmasks. */ + +/* Set for a private base class, clear for a public base class. + Protected base classes are not supported. */ +#define BASEFLAGS_PRIVATE (0x1) +/* Set for a virtual base class. */ +#define BASEFLAGS_VIRTUAL (0x2) +/* Set for a friend class, clear for a base class. */ +#define BASEFLAGS_FRIEND (0x10) + +/* These are the values found in the specs flags of a 'd', 'm', or 'v' + component record of a 'T' type extension record in a C++ pmisc + record. The same flags are used for a 'M' record in a C++ pmisc + record. */ + +/* The lower two bits hold visibility information. */ +#define CXXFLAGS_VISIBILITY (0x3) +/* This value in the lower two bits indicates a public member. */ +#define CXXFLAGS_VISIBILITY_PUBLIC (0x0) +/* This value in the lower two bits indicates a private member. */ +#define CXXFLAGS_VISIBILITY_PRIVATE (0x1) +/* This value in the lower two bits indicates a protected member. */ +#define CXXFLAGS_VISIBILITY_PROTECTED (0x2) +/* Set for a static member. */ +#define CXXFLAGS_STATIC (0x4) +/* Set for a virtual override. */ +#define CXXFLAGS_OVERRIDE (0x8) +/* Set for a friend function. */ +#define CXXFLAGS_FRIEND (0x10) +/* Set for a const function. */ +#define CXXFLAGS_CONST (0x20) +/* Set for a volatile function. */ +#define CXXFLAGS_VOLATILE (0x40) +/* Set for an overloaded function. */ +#define CXXFLAGS_OVERLOADED (0x80) +/* Set for an operator function. */ +#define CXXFLAGS_OPERATOR (0x100) +/* Set for a constructor or destructor. */ +#define CXXFLAGS_CTORDTOR (0x400) +/* Set for a constructor. */ +#define CXXFLAGS_CTOR (0x200) +/* Set for an inline function. */ +#define CXXFLAGS_INLINE (0x800) + +/* Local functions. */ + +static void ieee_error + PARAMS ((struct ieee_info *, const bfd_byte *, const char *)); +static void ieee_eof PARAMS ((struct ieee_info *)); +static char *savestring PARAMS ((const char *, unsigned long)); +static boolean ieee_read_number + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static boolean ieee_read_optional_number + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *, boolean *)); +static boolean ieee_read_id + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *)); +static boolean ieee_read_optional_id + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *, boolean *)); +static boolean ieee_read_expression + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static debug_type ieee_builtin_type + PARAMS ((struct ieee_info *, const bfd_byte *, unsigned int)); +static boolean ieee_alloc_type + PARAMS ((struct ieee_info *, unsigned int, boolean)); +static boolean ieee_read_type_index + PARAMS ((struct ieee_info *, const bfd_byte **, debug_type *)); +static int ieee_regno_to_genreg PARAMS ((bfd *, int)); +static int ieee_genreg_to_regno PARAMS ((bfd *, int)); +static boolean parse_ieee_bb PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean parse_ieee_be PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean parse_ieee_nn PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean parse_ieee_ty PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean parse_ieee_atn PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean ieee_read_cxx_misc + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static boolean ieee_read_cxx_class + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static boolean ieee_read_cxx_defaults + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static boolean ieee_read_reference + PARAMS ((struct ieee_info *, const bfd_byte **)); +static boolean ieee_require_asn + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static boolean ieee_require_atn65 + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *)); + +/* Report an error in the IEEE debugging information. */ + +static void +ieee_error (info, p, s) + struct ieee_info *info; + const bfd_byte *p; + const char *s; +{ + if (p != NULL) + fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd), + (unsigned long) (p - info->bytes), s, *p); + else + fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s); +} + +/* Report an unexpected EOF in the IEEE debugging information. */ + +static void +ieee_eof (info) + struct ieee_info *info; +{ + ieee_error (info, (const bfd_byte *) NULL, + "unexpected end of debugging information"); +} + +/* Save a string in memory. */ + +static char * +savestring (start, len) + const char *start; + unsigned long len; +{ + char *ret; + + ret = (char *) xmalloc (len + 1); + memcpy (ret, start, len); + ret[len] = '\0'; + return ret; +} + +/* Read a number which must be present in an IEEE file. */ + +static boolean +ieee_read_number (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + return ieee_read_optional_number (info, pp, pv, (boolean *) NULL); +} + +/* Read a number in an IEEE file. If ppresent is not NULL, the number + need not be there. */ + +static boolean +ieee_read_optional_number (info, pp, pv, ppresent) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; + boolean *ppresent; +{ + ieee_record_enum_type b; + + if (*pp >= info->pend) + { + if (ppresent != NULL) + { + *ppresent = false; + return true; + } + ieee_eof (info); + return false; + } + + b = (ieee_record_enum_type) **pp; + ++*pp; + + if (b <= ieee_number_end_enum) + { + *pv = (bfd_vma) b; + if (ppresent != NULL) + *ppresent = true; + return true; + } + + if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum) + { + unsigned int i; + + i = (int) b - (int) ieee_number_repeat_start_enum; + if (*pp + i - 1 >= info->pend) + { + ieee_eof (info); + return false; + } + + *pv = 0; + for (; i > 0; i--) + { + *pv <<= 8; + *pv += **pp; + ++*pp; + } + + if (ppresent != NULL) + *ppresent = true; + + return true; + } + + if (ppresent != NULL) + { + --*pp; + *ppresent = false; + return true; + } + + ieee_error (info, *pp - 1, "invalid number"); + return false; +} + +/* Read a required string from an IEEE file. */ + +static boolean +ieee_read_id (info, pp, pname, pnamlen) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; +{ + return ieee_read_optional_id (info, pp, pname, pnamlen, (boolean *) NULL); +} + +/* Read a string from an IEEE file. If ppresent is not NULL, the + string is optional. */ + +static boolean +ieee_read_optional_id (info, pp, pname, pnamlen, ppresent) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; + boolean *ppresent; +{ + bfd_byte b; + unsigned long len; + + if (*pp >= info->pend) + { + ieee_eof (info); + return false; + } + + b = **pp; + ++*pp; + + if (b <= 0x7f) + len = b; + else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum) + { + len = **pp; + ++*pp; + } + else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum) + { + len = (**pp << 8) + (*pp)[1]; + *pp += 2; + } + else + { + if (ppresent != NULL) + { + --*pp; + *ppresent = false; + return true; + } + ieee_error (info, *pp - 1, "invalid string length"); + return false; + } + + if ((unsigned long) (info->pend - *pp) < len) + { + ieee_eof (info); + return false; + } + + *pname = (const char *) *pp; + *pnamlen = len; + *pp += len; + + if (ppresent != NULL) + *ppresent = true; + + return true; +} + +/* Read an expression from an IEEE file. Since this code is only used + to parse debugging information, I haven't bothered to write a full + blown IEEE expression parser. I've only thrown in the things I've + seen in debugging information. This can be easily extended if + necessary. */ + +static boolean +ieee_read_expression (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + const bfd_byte *expr_start; +#define EXPR_STACK_SIZE (10) + bfd_vma expr_stack[EXPR_STACK_SIZE]; + bfd_vma *esp; + + expr_start = *pp; + + esp = expr_stack; + + while (1) + { + const bfd_byte *start; + bfd_vma val; + boolean present; + ieee_record_enum_type c; + + start = *pp; + + if (! ieee_read_optional_number (info, pp, &val, &present)) + return false; + + if (present) + { + if (esp - expr_stack >= EXPR_STACK_SIZE) + { + ieee_error (info, start, "expression stack overflow"); + return false; + } + *esp++ = val; + continue; + } + + c = (ieee_record_enum_type) **pp; + + if (c >= ieee_module_beginning_enum) + break; + + ++*pp; + + if (c == ieee_comma) + break; + + switch (c) + { + default: + ieee_error (info, start, "unsupported IEEE expression operator"); + break; + + case ieee_variable_R_enum: + { + bfd_vma indx; + asection *s; + + if (! ieee_read_number (info, pp, &indx)) + return false; + for (s = info->abfd->sections; s != NULL; s = s->next) + if ((bfd_vma) s->target_index == indx) + break; + if (s == NULL) + { + ieee_error (info, start, "unknown section"); + return false; + } + + if (esp - expr_stack >= EXPR_STACK_SIZE) + { + ieee_error (info, start, "expression stack overflow"); + return false; + } + + *esp++ = bfd_get_section_vma (info->abfd, s); + } + break; + + case ieee_function_plus_enum: + case ieee_function_minus_enum: + { + bfd_vma v1, v2; + + if (esp - expr_stack < 2) + { + ieee_error (info, start, "expression stack underflow"); + return false; + } + + v1 = *--esp; + v2 = *--esp; + *esp++ = v1 + v2; + } + break; + } + } + + if (esp - 1 != expr_stack) + { + ieee_error (info, expr_start, "expression stack mismatch"); + return false; + } + + *pv = *--esp; + + return true; +} + +/* Return an IEEE builtin type. */ + +static debug_type +ieee_builtin_type (info, p, indx) + struct ieee_info *info; + const bfd_byte *p; + unsigned int indx; +{ + PTR dhandle; + debug_type type; + const char *name; + + if (indx < BUILTIN_TYPE_COUNT + && info->types.builtins[indx] != DEBUG_TYPE_NULL) + return info->types.builtins[indx]; + + dhandle = info->dhandle; + + if (indx >= 32 && indx < 64) + { + type = debug_make_pointer_type (dhandle, + ieee_builtin_type (info, p, indx - 32)); + assert (indx < BUILTIN_TYPE_COUNT); + info->types.builtins[indx] = type; + return type; + } + + switch ((enum builtin_types) indx) + { + default: + ieee_error (info, p, "unknown builtin type"); + return NULL; + + case builtin_unknown: + type = debug_make_void_type (dhandle); + name = NULL; + break; + + case builtin_void: + type = debug_make_void_type (dhandle); + name = "void"; + break; + + case builtin_signed_char: + type = debug_make_int_type (dhandle, 1, false); + name = "signed char"; + break; + + case builtin_unsigned_char: + type = debug_make_int_type (dhandle, 1, true); + name = "unsigned char"; + break; + + case builtin_signed_short_int: + type = debug_make_int_type (dhandle, 2, false); + name = "signed short int"; + break; + + case builtin_unsigned_short_int: + type = debug_make_int_type (dhandle, 2, true); + name = "unsigned short int"; + break; + + case builtin_signed_long: + type = debug_make_int_type (dhandle, 4, false); + name = "signed long"; + break; + + case builtin_unsigned_long: + type = debug_make_int_type (dhandle, 4, true); + name = "unsigned long"; + break; + + case builtin_signed_long_long: + type = debug_make_int_type (dhandle, 8, false); + name = "signed long long"; + break; + + case builtin_unsigned_long_long: + type = debug_make_int_type (dhandle, 8, true); + name = "unsigned long long"; + break; + + case builtin_float: + type = debug_make_float_type (dhandle, 4); + name = "float"; + break; + + case builtin_double: + type = debug_make_float_type (dhandle, 8); + name = "double"; + break; + + case builtin_long_double: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_float_type (dhandle, 12); + name = "long double"; + break; + + case builtin_long_long_double: + type = debug_make_float_type (dhandle, 16); + name = "long long double"; + break; + + case builtin_quoted_string: + type = debug_make_array_type (dhandle, + ieee_builtin_type (info, p, + ((unsigned int) + builtin_char)), + ieee_builtin_type (info, p, + ((unsigned int) + builtin_int)), + 0, -1, true); + name = "QUOTED STRING"; + break; + + case builtin_instruction_address: + /* FIXME: This should be a code address. */ + type = debug_make_int_type (dhandle, 4, true); + name = "instruction address"; + break; + + case builtin_int: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, false); + name = "int"; + break; + + case builtin_unsigned: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, true); + name = "unsigned"; + break; + + case builtin_unsigned_int: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, true); + name = "unsigned int"; + break; + + case builtin_char: + type = debug_make_int_type (dhandle, 1, false); + name = "char"; + break; + + case builtin_long: + type = debug_make_int_type (dhandle, 4, false); + name = "long"; + break; + + case builtin_short: + type = debug_make_int_type (dhandle, 2, false); + name = "short"; + break; + + case builtin_unsigned_short: + type = debug_make_int_type (dhandle, 2, true); + name = "unsigned short"; + break; + + case builtin_short_int: + type = debug_make_int_type (dhandle, 2, false); + name = "short int"; + break; + + case builtin_signed_short: + type = debug_make_int_type (dhandle, 2, false); + name = "signed short"; + break; + + case builtin_bcd_float: + ieee_error (info, p, "BCD float type not supported"); + return DEBUG_TYPE_NULL; + } + + if (name != NULL) + type = debug_name_type (dhandle, name, type); + + assert (indx < BUILTIN_TYPE_COUNT); + + info->types.builtins[indx] = type; + + return type; +} + +/* Allocate more space in the type table. If ref is true, this is a + reference to the type; if it is not already defined, we should set + up an indirect type. */ + +static boolean +ieee_alloc_type (info, indx, ref) + struct ieee_info *info; + unsigned int indx; + boolean ref; +{ + unsigned int nalloc; + register struct ieee_type *t; + struct ieee_type *tend; + + if (indx >= info->types.alloc) + { + nalloc = info->types.alloc; + if (nalloc == 0) + nalloc = 4; + while (indx >= nalloc) + nalloc *= 2; + + info->types.types = ((struct ieee_type *) + xrealloc (info->types.types, + nalloc * sizeof *info->types.types)); + + memset (info->types.types + info->types.alloc, 0, + (nalloc - info->types.alloc) * sizeof *info->types.types); + + tend = info->types.types + nalloc; + for (t = info->types.types + info->types.alloc; t < tend; t++) + t->type = DEBUG_TYPE_NULL; + + info->types.alloc = nalloc; + } + + if (ref) + { + t = info->types.types + indx; + if (t->type == NULL) + { + t->pslot = (debug_type *) xmalloc (sizeof *t->pslot); + *t->pslot = DEBUG_TYPE_NULL; + t->type = debug_make_indirect_type (info->dhandle, t->pslot, + (const char *) NULL); + if (t->type == NULL) + return false; + } + } + + return true; +} + +/* Read a type index and return the corresponding type. */ + +static boolean +ieee_read_type_index (info, pp, ptype) + struct ieee_info *info; + const bfd_byte **pp; + debug_type *ptype; +{ + const bfd_byte *start; + bfd_vma indx; + + start = *pp; + + if (! ieee_read_number (info, pp, &indx)) + return false; + + if (indx < 256) + { + *ptype = ieee_builtin_type (info, start, indx); + if (*ptype == NULL) + return false; + return true; + } + + indx -= 256; + if (! ieee_alloc_type (info, indx, true)) + return false; + + *ptype = info->types.types[indx].type; + + return true; +} + +/* Parse IEEE debugging information for a file. This is passed the + bytes which compose the Debug Information Part of an IEEE file. */ + +boolean +parse_ieee (dhandle, abfd, bytes, len) + PTR dhandle; + bfd *abfd; + const bfd_byte *bytes; + bfd_size_type len; +{ + struct ieee_info info; + unsigned int i; + const bfd_byte *p, *pend; + + info.dhandle = dhandle; + info.abfd = abfd; + info.bytes = bytes; + info.pend = bytes + len; + info.blockstack.bsp = info.blockstack.stack; + info.saw_filename = false; + info.vars.alloc = 0; + info.vars.vars = NULL; + info.types.alloc = 0; + info.types.types = NULL; + info.tags = NULL; + for (i = 0; i < BUILTIN_TYPE_COUNT; i++) + info.types.builtins[i] = DEBUG_TYPE_NULL; + + p = bytes; + pend = info.pend; + while (p < pend) + { + const bfd_byte *record_start; + ieee_record_enum_type c; + + record_start = p; + + c = (ieee_record_enum_type) *p++; + + if (c == ieee_at_record_enum) + c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++); + + if (c <= ieee_number_repeat_end_enum) + { + ieee_error (&info, record_start, "unexpected number"); + return false; + } + + switch (c) + { + default: + ieee_error (&info, record_start, "unexpected record type"); + return false; + + case ieee_bb_record_enum: + if (! parse_ieee_bb (&info, &p)) + return false; + break; + + case ieee_be_record_enum: + if (! parse_ieee_be (&info, &p)) + return false; + break; + + case ieee_nn_record: + if (! parse_ieee_nn (&info, &p)) + return false; + break; + + case ieee_ty_record_enum: + if (! parse_ieee_ty (&info, &p)) + return false; + break; + + case ieee_atn_record_enum: + if (! parse_ieee_atn (&info, &p)) + return false; + break; + } + } + + if (info.blockstack.bsp != info.blockstack.stack) + { + ieee_error (&info, (const bfd_byte *) NULL, + "blocks left on stack at end"); + return false; + } + + return true; +} + +/* Handle an IEEE BB record. */ + +static boolean +parse_ieee_bb (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *block_start; + bfd_byte b; + bfd_vma size; + const char *name; + unsigned long namlen; + char *namcopy = NULL; + unsigned int fnindx; + boolean skip; + + block_start = *pp; + + b = **pp; + ++*pp; + + if (! ieee_read_number (info, pp, &size) + || ! ieee_read_id (info, pp, &name, &namlen)) + return false; + + fnindx = (unsigned int) -1; + skip = false; + + switch (b) + { + case 1: + /* BB1: Type definitions local to a module. */ + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return false; + if (! debug_set_filename (info->dhandle, namcopy)) + return false; + info->saw_filename = true; + + /* Discard any variables or types we may have seen before. */ + if (info->vars.vars != NULL) + free (info->vars.vars); + info->vars.vars = NULL; + info->vars.alloc = 0; + if (info->types.types != NULL) + free (info->types.types); + info->types.types = NULL; + info->types.alloc = 0; + + /* Initialize the types to the global types. */ + if (info->global_types != NULL) + { + info->types.alloc = info->global_types->alloc; + info->types.types = ((struct ieee_type *) + xmalloc (info->types.alloc + * sizeof (*info->types.types))); + memcpy (info->types.types, info->global_types->types, + info->types.alloc * sizeof (*info->types.types)); + } + + break; + + case 2: + /* BB2: Global type definitions. The name is supposed to be + empty, but we don't check. */ + if (! debug_set_filename (info->dhandle, "*global*")) + return false; + info->saw_filename = true; + break; + + case 3: + /* BB3: High level module block begin. We don't have to do + anything here. The name is supposed to be the same as for + the BB1, but we don't check. */ + break; + + case 4: + /* BB4: Global function. */ + { + bfd_vma stackspace, typindx, offset; + debug_type return_type; + + if (! ieee_read_number (info, pp, &stackspace) + || ! ieee_read_number (info, pp, &typindx) + || ! ieee_read_expression (info, pp, &offset)) + return false; + + /* We have no way to record the stack space. FIXME. */ + + if (typindx < 256) + { + return_type = ieee_builtin_type (info, block_start, typindx); + if (return_type == DEBUG_TYPE_NULL) + return false; + } + else + { + typindx -= 256; + if (! ieee_alloc_type (info, typindx, true)) + return false; + fnindx = typindx; + return_type = info->types.types[typindx].type; + if (debug_get_type_kind (info->dhandle, return_type) + == DEBUG_KIND_FUNCTION) + return_type = debug_get_return_type (info->dhandle, + return_type); + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return false; + if (! debug_record_function (info->dhandle, namcopy, return_type, + true, offset)) + return false; + } + break; + + case 5: + /* BB5: File name for source line numbers. */ + { + unsigned int i; + + /* We ignore the date and time. FIXME. */ + for (i = 0; i < 6; i++) + { + bfd_vma ignore; + boolean present; + + if (! ieee_read_optional_number (info, pp, &ignore, &present)) + return false; + if (! present) + break; + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return false; + if (! debug_start_source (info->dhandle, namcopy)) + return false; + } + break; + + case 6: + /* BB6: Local function or block. */ + { + bfd_vma stackspace, typindx, offset; + + if (! ieee_read_number (info, pp, &stackspace) + || ! ieee_read_number (info, pp, &typindx) + || ! ieee_read_expression (info, pp, &offset)) + return false; + + /* We have no way to record the stack space. FIXME. */ + + if (namlen == 0) + { + if (! debug_start_block (info->dhandle, offset)) + return false; + /* Change b to indicate that this is a block + rather than a function. */ + b = 0x86; + } + else + { + /* The MRI C++ compiler will output a fake function named + __XRYCPP to hold C++ debugging information. We skip + that function. This is not crucial, but it makes + converting from IEEE to other debug formats work + better. */ + if (strncmp (name, "__XRYCPP", namlen) == 0) + skip = true; + else + { + debug_type return_type; + + if (typindx < 256) + { + return_type = ieee_builtin_type (info, block_start, + typindx); + if (return_type == NULL) + return false; + } + else + { + typindx -= 256; + if (! ieee_alloc_type (info, typindx, true)) + return false; + fnindx = typindx; + return_type = info->types.types[typindx].type; + if (debug_get_type_kind (info->dhandle, return_type) + == DEBUG_KIND_FUNCTION) + return_type = debug_get_return_type (info->dhandle, + return_type); + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return false; + if (! debug_record_function (info->dhandle, namcopy, + return_type, false, offset)) + return false; + } + } + } + break; + + case 10: + /* BB10: Assembler module scope. In the normal case, we + completely ignore all this information. FIXME. */ + { + const char *inam, *vstr; + unsigned long inamlen, vstrlen; + bfd_vma tool_type; + boolean present; + unsigned int i; + + if (! info->saw_filename) + { + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return false; + if (! debug_set_filename (info->dhandle, namcopy)) + return false; + info->saw_filename = true; + } + + if (! ieee_read_id (info, pp, &inam, &inamlen) + || ! ieee_read_number (info, pp, &tool_type) + || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present)) + return false; + for (i = 0; i < 6; i++) + { + bfd_vma ignore; + + if (! ieee_read_optional_number (info, pp, &ignore, &present)) + return false; + if (! present) + break; + } + } + break; + + case 11: + /* BB11: Module section. We completely ignore all this + information. FIXME. */ + { + bfd_vma sectype, secindx, offset, map; + boolean present; + + if (! ieee_read_number (info, pp, §ype) + || ! ieee_read_number (info, pp, &secindx) + || ! ieee_read_expression (info, pp, &offset) + || ! ieee_read_optional_number (info, pp, &map, &present)) + return false; + } + break; + + default: + ieee_error (info, block_start, "unknown BB type"); + return false; + } + + + /* Push this block on the block stack. */ + + if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE) + { + ieee_error (info, (const bfd_byte *) NULL, "stack overflow"); + return false; + } + + info->blockstack.bsp->kind = b; + if (b == 5) + info->blockstack.bsp->filename = namcopy; + info->blockstack.bsp->fnindx = fnindx; + info->blockstack.bsp->skip = skip; + ++info->blockstack.bsp; + + return true; +} + +/* Handle an IEEE BE record. */ + +static boolean +parse_ieee_be (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + bfd_vma offset; + + if (info->blockstack.bsp <= info->blockstack.stack) + { + ieee_error (info, *pp, "stack underflow"); + return false; + } + --info->blockstack.bsp; + + switch (info->blockstack.bsp->kind) + { + case 2: + /* When we end the global typedefs block, we copy out the the + contents of info->vars. This is because the variable indices + may be reused in the local blocks. However, we need to + preserve them so that we can locate a function returning a + reference variable whose type is named in the global typedef + block. */ + info->global_vars = ((struct ieee_vars *) + xmalloc (sizeof *info->global_vars)); + info->global_vars->alloc = info->vars.alloc; + info->global_vars->vars = ((struct ieee_var *) + xmalloc (info->vars.alloc + * sizeof (*info->vars.vars))); + memcpy (info->global_vars->vars, info->vars.vars, + info->vars.alloc * sizeof (*info->vars.vars)); + + /* We also copy out the non builtin parts of info->types, since + the types are discarded when we start a new block. */ + info->global_types = ((struct ieee_types *) + xmalloc (sizeof *info->global_types)); + info->global_types->alloc = info->types.alloc; + info->global_types->types = ((struct ieee_type *) + xmalloc (info->types.alloc + * sizeof (*info->types.types))); + memcpy (info->global_types->types, info->types.types, + info->types.alloc * sizeof (*info->types.types)); + memset (info->global_types->builtins, 0, + sizeof (info->global_types->builtins)); + + break; + + case 4: + case 6: + if (! ieee_read_expression (info, pp, &offset)) + return false; + if (! info->blockstack.bsp->skip) + { + if (! debug_end_function (info->dhandle, offset + 1)) + return false; + } + break; + + case 0x86: + /* This is BE6 when BB6 started a block rather than a local + function. */ + if (! ieee_read_expression (info, pp, &offset)) + return false; + if (! debug_end_block (info->dhandle, offset + 1)) + return false; + break; + + case 5: + /* When we end a BB5, we look up the stack for the last BB5, if + there is one, so that we can call debug_start_source. */ + if (info->blockstack.bsp > info->blockstack.stack) + { + struct ieee_block *bl; + + bl = info->blockstack.bsp; + do + { + --bl; + if (bl->kind == 5) + { + if (! debug_start_source (info->dhandle, bl->filename)) + return false; + break; + } + } + while (bl != info->blockstack.stack); + } + break; + + case 11: + if (! ieee_read_expression (info, pp, &offset)) + return false; + /* We just ignore the module size. FIXME. */ + break; + + default: + /* Other block types do not have any trailing information. */ + break; + } + + return true; +} + +/* Parse an NN record. */ + +static boolean +parse_ieee_nn (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *nn_start; + bfd_vma varindx; + const char *name; + unsigned long namlen; + + nn_start = *pp; + + if (! ieee_read_number (info, pp, &varindx) + || ! ieee_read_id (info, pp, &name, &namlen)) + return false; + + if (varindx < 32) + { + ieee_error (info, nn_start, "illegal variable index"); + return false; + } + varindx -= 32; + + if (varindx >= info->vars.alloc) + { + unsigned int alloc; + + alloc = info->vars.alloc; + if (alloc == 0) + alloc = 4; + while (varindx >= alloc) + alloc *= 2; + info->vars.vars = ((struct ieee_var *) + xrealloc (info->vars.vars, + alloc * sizeof *info->vars.vars)); + memset (info->vars.vars + info->vars.alloc, 0, + (alloc - info->vars.alloc) * sizeof *info->vars.vars); + info->vars.alloc = alloc; + } + + info->vars.vars[varindx].name = name; + info->vars.vars[varindx].namlen = namlen; + + return true; +} + +/* Parse a TY record. */ + +static boolean +parse_ieee_ty (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *ty_start, *ty_var_start, *ty_code_start; + bfd_vma typeindx, varindx, tc; + PTR dhandle; + boolean tag, typdef; + debug_type *arg_slots; + unsigned long type_bitsize; + debug_type type; + + ty_start = *pp; + + if (! ieee_read_number (info, pp, &typeindx)) + return false; + + if (typeindx < 256) + { + ieee_error (info, ty_start, "illegal type index"); + return false; + } + + typeindx -= 256; + if (! ieee_alloc_type (info, typeindx, false)) + return false; + + if (**pp != 0xce) + { + ieee_error (info, *pp, "unknown TY code"); + return false; + } + ++*pp; + + ty_var_start = *pp; + + if (! ieee_read_number (info, pp, &varindx)) + return false; + + if (varindx < 32) + { + ieee_error (info, ty_var_start, "illegal variable index"); + return false; + } + varindx -= 32; + + if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL) + { + ieee_error (info, ty_var_start, "undefined variable in TY"); + return false; + } + + ty_code_start = *pp; + + if (! ieee_read_number (info, pp, &tc)) + return false; + + dhandle = info->dhandle; + + tag = false; + typdef = false; + arg_slots = NULL; + type_bitsize = 0; + switch (tc) + { + default: + ieee_error (info, ty_code_start, "unknown TY code"); + return false; + + case '!': + /* Unknown type, with size. We treat it as int. FIXME. */ + { + bfd_vma size; + + if (! ieee_read_number (info, pp, &size)) + return false; + type = debug_make_int_type (dhandle, size, false); + } + break; + + case 'A': /* Array. */ + case 'a': /* FORTRAN array in column/row order. FIXME: Not + distinguished from normal array. */ + { + debug_type ele_type; + bfd_vma lower, upper; + + if (! ieee_read_type_index (info, pp, &ele_type) + || ! ieee_read_number (info, pp, &lower) + || ! ieee_read_number (info, pp, &upper)) + return false; + type = debug_make_array_type (dhandle, ele_type, + ieee_builtin_type (info, ty_code_start, + ((unsigned int) + builtin_int)), + (bfd_signed_vma) lower, + (bfd_signed_vma) upper, + false); + } + break; + + case 'E': + /* Simple enumeration. */ + { + bfd_vma size; + unsigned int alloc; + const char **names; + unsigned int c; + bfd_signed_vma *vals; + unsigned int i; + + if (! ieee_read_number (info, pp, &size)) + return false; + /* FIXME: we ignore the enumeration size. */ + + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + memset (names, 0, alloc * sizeof *names); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + boolean present; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + if (! present) + break; + + if (c + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc (names, alloc * sizeof *names)); + } + + names[c] = savestring (name, namlen); + if (names[c] == NULL) + return false; + ++c; + } + + names[c] = NULL; + + vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals); + for (i = 0; i < c; i++) + vals[i] = i; + + type = debug_make_enum_type (dhandle, names, vals); + tag = true; + } + break; + + case 'G': + /* Struct with bit fields. */ + { + bfd_vma size; + unsigned int alloc; + debug_field *fields; + unsigned int c; + + if (! ieee_read_number (info, pp, &size)) + return false; + + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + boolean present; + debug_type ftype; + bfd_vma bitpos, bitsize; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + if (! present) + break; + if (! ieee_read_type_index (info, pp, &ftype) + || ! ieee_read_number (info, pp, &bitpos) + || ! ieee_read_number (info, pp, &bitsize)) + return false; + + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc (fields, alloc * sizeof *fields)); + } + + fields[c] = debug_make_field (dhandle, savestring (name, namlen), + ftype, bitpos, bitsize, + DEBUG_VISIBILITY_PUBLIC); + if (fields[c] == NULL) + return false; + ++c; + } + + fields[c] = NULL; + + type = debug_make_struct_type (dhandle, true, size, fields); + tag = true; + } + break; + + case 'N': + /* Enumeration. */ + { + unsigned int alloc; + const char **names; + bfd_signed_vma *vals; + unsigned int c; + + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + boolean present; + bfd_vma val; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + if (! present) + break; + if (! ieee_read_number (info, pp, &val)) + return false; + + /* If the length of the name is zero, then the value is + actually the size of the enum. We ignore this + information. FIXME. */ + if (namlen == 0) + continue; + + if (c + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc (names, alloc * sizeof *names)); + vals = ((bfd_signed_vma *) + xrealloc (vals, alloc * sizeof *vals)); + } + + names[c] = savestring (name, namlen); + if (names[c] == NULL) + return false; + vals[c] = (bfd_signed_vma) val; + ++c; + } + + names[c] = NULL; + + type = debug_make_enum_type (dhandle, names, vals); + tag = true; + } + break; + + case 'O': /* Small pointer. We don't distinguish small and large + pointers. FIXME. */ + case 'P': /* Large pointer. */ + { + debug_type t; + + if (! ieee_read_type_index (info, pp, &t)) + return false; + type = debug_make_pointer_type (dhandle, t); + } + break; + + case 'R': + /* Range. */ + { + bfd_vma low, high, signedp, size; + + if (! ieee_read_number (info, pp, &low) + || ! ieee_read_number (info, pp, &high) + || ! ieee_read_number (info, pp, &signedp) + || ! ieee_read_number (info, pp, &size)) + return false; + + type = debug_make_range_type (dhandle, + debug_make_int_type (dhandle, size, + ! signedp), + (bfd_signed_vma) low, + (bfd_signed_vma) high); + } + break; + + case 'S': /* Struct. */ + case 'U': /* Union. */ + { + bfd_vma size; + unsigned int alloc; + debug_field *fields; + unsigned int c; + + if (! ieee_read_number (info, pp, &size)) + return false; + + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + boolean present; + bfd_vma tindx; + bfd_vma offset; + debug_type ftype; + bfd_vma bitsize; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + if (! present) + break; + if (! ieee_read_number (info, pp, &tindx) + || ! ieee_read_number (info, pp, &offset)) + return false; + + if (tindx < 256) + { + ftype = ieee_builtin_type (info, ty_code_start, tindx); + bitsize = 0; + offset *= 8; + } + else + { + struct ieee_type *t; + + tindx -= 256; + if (! ieee_alloc_type (info, tindx, true)) + return false; + t = info->types.types + tindx; + ftype = t->type; + bitsize = t->bitsize; + if (bitsize == 0) + offset *= 8; + } + + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc (fields, alloc * sizeof *fields)); + } + + fields[c] = debug_make_field (dhandle, savestring (name, namlen), + ftype, offset, bitsize, + DEBUG_VISIBILITY_PUBLIC); + if (fields[c] == NULL) + return false; + ++c; + } + + fields[c] = NULL; + + type = debug_make_struct_type (dhandle, tc == 'S', size, fields); + tag = true; + } + break; + + case 'T': + /* Typedef. */ + if (! ieee_read_type_index (info, pp, &type)) + return false; + typdef = true; + break; + + case 'X': + /* Procedure. FIXME: This is an extern declaration, which we + have no way of representing. */ + { + bfd_vma attr; + debug_type rtype; + bfd_vma nargs; + boolean present; + struct ieee_var *pv; + + /* FIXME: We ignore the attribute and the argument names. */ + + if (! ieee_read_number (info, pp, &attr) + || ! ieee_read_type_index (info, pp, &rtype) + || ! ieee_read_number (info, pp, &nargs)) + return false; + do + { + const char *name; + unsigned long namlen; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + } + while (present); + + pv = info->vars.vars + varindx; + pv->kind = IEEE_EXTERNAL; + if (pv->namlen > 0 + && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) + { + /* Set up the return type as an indirect type pointing to + the variable slot, so that we can change it to a + reference later if appropriate. */ + pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); + *pv->pslot = rtype; + rtype = debug_make_indirect_type (dhandle, pv->pslot, + (const char *) NULL); + } + + type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL, + false); + } + break; + + case 'V': + /* Void. This is not documented, but the MRI compiler emits it. */ + type = debug_make_void_type (dhandle); + break; + + case 'Z': + /* Array with 0 lower bound. */ + { + debug_type etype; + bfd_vma high; + + if (! ieee_read_type_index (info, pp, &etype) + || ! ieee_read_number (info, pp, &high)) + return false; + + type = debug_make_array_type (dhandle, etype, + ieee_builtin_type (info, ty_code_start, + ((unsigned int) + builtin_int)), + 0, (bfd_signed_vma) high, false); + } + break; + + case 'c': /* Complex. */ + case 'd': /* Double complex. */ + { + const char *name; + unsigned long namlen; + + /* FIXME: I don't know what the name means. */ + + if (! ieee_read_id (info, pp, &name, &namlen)) + return false; + + type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8); + } + break; + + case 'f': + /* Pascal file name. FIXME. */ + ieee_error (info, ty_code_start, "Pascal file name not supported"); + return false; + + case 'g': + /* Bitfield type. */ + { + bfd_vma signedp, bitsize, dummy; + const bfd_byte *hold; + boolean present; + + if (! ieee_read_number (info, pp, &signedp) + || ! ieee_read_number (info, pp, &bitsize)) + return false; + + /* I think the documentation says that there is a type index, + but some actual files do not have one. */ + hold = *pp; + if (! ieee_read_optional_number (info, pp, &dummy, &present)) + return false; + if (! present) + { + /* FIXME: This is just a guess. */ + type = debug_make_int_type (dhandle, 4, + signedp ? false : true); + } + else + { + *pp = hold; + if (! ieee_read_type_index (info, pp, &type)) + return false; + } + type_bitsize = bitsize; + } + break; + + case 'n': + /* Qualifier. */ + { + bfd_vma kind; + debug_type t; + + if (! ieee_read_number (info, pp, &kind) + || ! ieee_read_type_index (info, pp, &t)) + return false; + + switch (kind) + { + default: + ieee_error (info, ty_start, "unsupported qualifer"); + return false; + + case 1: + type = debug_make_const_type (dhandle, t); + break; + + case 2: + type = debug_make_volatile_type (dhandle, t); + break; + } + } + break; + + case 's': + /* Set. */ + { + bfd_vma size; + debug_type etype; + + if (! ieee_read_number (info, pp, &size) + || ! ieee_read_type_index (info, pp, &etype)) + return false; + + /* FIXME: We ignore the size. */ + + type = debug_make_set_type (dhandle, etype, false); + } + break; + + case 'x': + /* Procedure with compiler dependencies. */ + { + struct ieee_var *pv; + bfd_vma attr, frame_type, push_mask, nargs, level, father; + debug_type rtype; + debug_type *arg_types; + boolean varargs; + boolean present; + + /* FIXME: We ignore some of this information. */ + + pv = info->vars.vars + varindx; + + if (! ieee_read_number (info, pp, &attr) + || ! ieee_read_number (info, pp, &frame_type) + || ! ieee_read_number (info, pp, &push_mask) + || ! ieee_read_type_index (info, pp, &rtype) + || ! ieee_read_number (info, pp, &nargs)) + return false; + if (nargs == (bfd_vma) -1) + { + arg_types = NULL; + varargs = false; + } + else + { + unsigned int i; + + arg_types = ((debug_type *) + xmalloc ((nargs + 1) * sizeof *arg_types)); + for (i = 0; i < nargs; i++) + if (! ieee_read_type_index (info, pp, arg_types + i)) + return false; + + /* If the last type is pointer to void, this is really a + varargs function. */ + varargs = false; + if (nargs > 0) + { + debug_type last; + + last = arg_types[nargs - 1]; + if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER + && (debug_get_type_kind (dhandle, + debug_get_target_type (dhandle, + last)) + == DEBUG_KIND_VOID)) + { + --nargs; + varargs = true; + } + } + + /* If there are any pointer arguments, turn them into + indirect types in case we later need to convert them to + reference types. */ + for (i = 0; i < nargs; i++) + { + if (debug_get_type_kind (dhandle, arg_types[i]) + == DEBUG_KIND_POINTER) + { + if (arg_slots == NULL) + { + arg_slots = ((debug_type *) + xmalloc (nargs * sizeof *arg_slots)); + memset (arg_slots, 0, nargs * sizeof *arg_slots); + } + arg_slots[i] = arg_types[i]; + arg_types[i] = + debug_make_indirect_type (dhandle, + arg_slots + i, + (const char *) NULL); + } + } + + arg_types[nargs] = DEBUG_TYPE_NULL; + } + if (! ieee_read_number (info, pp, &level) + || ! ieee_read_optional_number (info, pp, &father, &present)) + return false; + + /* We can't distinguish between a global function and a static + function. */ + pv->kind = IEEE_FUNCTION; + + if (pv->namlen > 0 + && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) + { + /* Set up the return type as an indirect type pointing to + the variable slot, so that we can change it to a + reference later if appropriate. */ + pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); + *pv->pslot = rtype; + rtype = debug_make_indirect_type (dhandle, pv->pslot, + (const char *) NULL); + } + + type = debug_make_function_type (dhandle, rtype, arg_types, varargs); + } + break; + } + + /* Record the type in the table. */ + + if (type == DEBUG_TYPE_NULL) + return false; + + info->vars.vars[varindx].type = type; + + if ((tag || typdef) + && info->vars.vars[varindx].namlen > 0) + { + const char *name; + + name = savestring (info->vars.vars[varindx].name, + info->vars.vars[varindx].namlen); + if (typdef) + type = debug_name_type (dhandle, name, type); + else if (tc == 'E' || tc == 'N') + type = debug_tag_type (dhandle, name, type); + else + { + struct ieee_tag *it; + + /* We must allocate all struct tags as indirect types, so + that if we later see a definition of the tag as a C++ + record we can update the indirect slot and automatically + change all the existing references. */ + it = (struct ieee_tag *) xmalloc (sizeof *it); + memset (it, 0, sizeof *it); + it->next = info->tags; + info->tags = it; + it->name = name; + it->slot = type; + + type = debug_make_indirect_type (dhandle, &it->slot, name); + type = debug_tag_type (dhandle, name, type); + + it->type = type; + } + if (type == NULL) + return false; + } + + info->types.types[typeindx].type = type; + info->types.types[typeindx].arg_slots = arg_slots; + info->types.types[typeindx].bitsize = type_bitsize; + + /* We may have already allocated type as an indirect type pointing + to slot. It does no harm to replace the indirect type with the + real type. Filling in slot as well handles the indirect types + which are already hanging around. */ + if (info->types.types[typeindx].pslot != NULL) + *info->types.types[typeindx].pslot = type; + + return true; +} + +/* Parse an ATN record. */ + +static boolean +parse_ieee_atn (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *atn_start, *atn_code_start; + bfd_vma varindx; + struct ieee_var *pvar; + debug_type type; + bfd_vma atn_code; + PTR dhandle; + bfd_vma v, v2, v3, v4, v5; + const char *name; + unsigned long namlen; + char *namcopy; + boolean present; + int blocktype; + + atn_start = *pp; + + if (! ieee_read_number (info, pp, &varindx) + || ! ieee_read_type_index (info, pp, &type)) + return false; + + atn_code_start = *pp; + + if (! ieee_read_number (info, pp, &atn_code)) + return false; + + if (varindx == 0) + { + pvar = NULL; + name = ""; + namlen = 0; + } + else if (varindx < 32) + { + ieee_error (info, atn_start, "illegal variable index"); + return false; + } + else + { + varindx -= 32; + if (varindx >= info->vars.alloc + || info->vars.vars[varindx].name == NULL) + { + /* The MRI compiler or linker sometimes omits the NN record + for a pmisc record. */ + if (atn_code == 62) + { + if (varindx >= info->vars.alloc) + { + unsigned int alloc; + + alloc = info->vars.alloc; + if (alloc == 0) + alloc = 4; + while (varindx >= alloc) + alloc *= 2; + info->vars.vars = ((struct ieee_var *) + xrealloc (info->vars.vars, + (alloc + * sizeof *info->vars.vars))); + memset (info->vars.vars + info->vars.alloc, 0, + ((alloc - info->vars.alloc) + * sizeof *info->vars.vars)); + info->vars.alloc = alloc; + } + + pvar = info->vars.vars + varindx; + pvar->name = ""; + pvar->namlen = 0; + } + else + { + ieee_error (info, atn_start, "undefined variable in ATN"); + return false; + } + } + + pvar = info->vars.vars + varindx; + + pvar->type = type; + + name = pvar->name; + namlen = pvar->namlen; + } + + dhandle = info->dhandle; + + /* If we are going to call debug_record_variable with a pointer + type, change the type to an indirect type so that we can later + change it to a reference type if we encounter a C++ pmisc 'R' + record. */ + if (pvar != NULL + && type != DEBUG_TYPE_NULL + && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER) + { + switch (atn_code) + { + case 1: + case 2: + case 3: + case 5: + case 8: + case 10: + pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot); + *pvar->pslot = type; + type = debug_make_indirect_type (dhandle, pvar->pslot, + (const char *) NULL); + pvar->type = type; + break; + } + } + + switch (atn_code) + { + default: + ieee_error (info, atn_code_start, "unknown ATN type"); + return false; + + case 1: + /* Automatic variable. */ + if (! ieee_read_number (info, pp, &v)) + return false; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v); + + case 2: + /* Register variable. */ + if (! ieee_read_number (info, pp, &v)) + return false; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, + ieee_regno_to_genreg (info->abfd, v)); + + case 3: + /* Static variable. */ + if (! ieee_require_asn (info, pp, &v)) + return false; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (info->blockstack.bsp <= info->blockstack.stack) + blocktype = 0; + else + blocktype = info->blockstack.bsp[-1].kind; + if (pvar != NULL) + { + if (blocktype == 4 || blocktype == 6) + pvar->kind = IEEE_LOCAL; + else + pvar->kind = IEEE_STATIC; + } + return debug_record_variable (dhandle, namcopy, type, + (blocktype == 4 || blocktype == 6 + ? DEBUG_LOCAL_STATIC + : DEBUG_STATIC), + v); + + case 4: + /* External function. We don't currently record these. FIXME. */ + if (pvar != NULL) + pvar->kind = IEEE_EXTERNAL; + return true; + + case 5: + /* External variable. We don't currently record these. FIXME. */ + if (pvar != NULL) + pvar->kind = IEEE_EXTERNAL; + return true; + + case 7: + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_number (info, pp, &v3, &present)) + return false; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v4, &present)) + return false; + } + + /* We just ignore the two optional fields in v3 and v4, since + they are not defined. */ + + if (! ieee_require_asn (info, pp, &v3)) + return false; + + /* We have no way to record the column number. FIXME. */ + + return debug_record_line (dhandle, v, v3); + + case 8: + /* Global variable. */ + if (! ieee_require_asn (info, pp, &v)) + return false; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_GLOBAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v); + + case 9: + /* Variable lifetime information. */ + if (! ieee_read_number (info, pp, &v)) + return false; + + /* We have no way to record this information. FIXME. */ + return true; + + case 10: + /* Locked register. The spec says that there are two required + fields, but at least on occasion the MRI compiler only emits + one. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present)) + return false; + + /* I think this means a variable that is both in a register and + a frame slot. We ignore the frame slot. FIXME. */ + + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v); + + case 11: + /* Reserved for FORTRAN common. */ + ieee_error (info, atn_code_start, "unsupported ATN11"); + + /* Return true to keep going. */ + return true; + + case 12: + /* Based variable. */ + v3 = 0; + v4 = 0x80; + v5 = 0; + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_number (info, pp, &v3, &present)) + return false; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v4, &present)) + return false; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v5, &present)) + return false; + } + } + + /* We have no way to record this information. FIXME. */ + + ieee_error (info, atn_code_start, "unsupported ATN12"); + + /* Return true to keep going. */ + return true; + + case 16: + /* Constant. The description of this that I have is ambiguous, + so I'm not going to try to implement it. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present)) + return false; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v2, &present)) + return false; + if (present) + { + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + } + } + + if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum) + { + if (! ieee_require_asn (info, pp, &v3)) + return false; + } + + return true; + + case 19: + /* Static variable from assembler. */ + v2 = 0; + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present) + || ! ieee_require_asn (info, pp, &v3)) + return false; + namcopy = savestring (name, namlen); + /* We don't really handle this correctly. FIXME. */ + return debug_record_variable (dhandle, namcopy, + debug_make_void_type (dhandle), + v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC, + v3); + + case 62: + /* Procedure miscellaneous information. */ + case 63: + /* Variable miscellaneous information. */ + case 64: + /* Module miscellaneous information. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return false; + + if (atn_code == 62 && v == 80) + { + if (present) + { + ieee_error (info, atn_code_start, + "unexpected string in C++ misc"); + return false; + } + return ieee_read_cxx_misc (info, pp, v2); + } + + /* We just ignore all of this stuff. FIXME. */ + + for (; v2 > 0; --v2) + { + switch ((ieee_record_enum_type) **pp) + { + default: + ieee_error (info, *pp, "bad misc record"); + return false; + + case ieee_at_record_enum: + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return false; + break; + + case ieee_e2_first_byte_enum: + if (! ieee_require_asn (info, pp, &v3)) + return false; + break; + } + } + + return true; + } + + /*NOTREACHED*/ +} + +/* Handle C++ debugging miscellaneous records. This is called for + procedure miscellaneous records of type 80. */ + +static boolean +ieee_read_cxx_misc (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + bfd_vma category; + + start = *pp; + + /* Get the category of C++ misc record. */ + if (! ieee_require_asn (info, pp, &category)) + return false; + --count; + + switch (category) + { + default: + ieee_error (info, start, "unrecognized C++ misc record"); + return false; + + case 'T': + if (! ieee_read_cxx_class (info, pp, count)) + return false; + break; + + case 'M': + { + bfd_vma flags; + const char *name; + unsigned long namlen; + + /* The IEEE spec indicates that the 'M' record only has a + flags field. The MRI compiler also emits the name of the + function. */ + + if (! ieee_require_asn (info, pp, &flags)) + return false; + if (*pp < info->pend + && (ieee_record_enum_type) **pp == ieee_at_record_enum) + { + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return false; + } + + /* This is emitted for method functions, but I don't think we + care very much. It might help if it told us useful + information like the class with which this function is + associated, but it doesn't, so it isn't helpful. */ + } + break; + + case 'B': + if (! ieee_read_cxx_defaults (info, pp, count)) + return false; + break; + + case 'z': + { + const char *name, *mangled, *class; + unsigned long namlen, mangledlen, classlen; + bfd_vma control; + + /* Pointer to member. */ + + if (! ieee_require_atn65 (info, pp, &name, &namlen) + || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen) + || ! ieee_require_atn65 (info, pp, &class, &classlen) + || ! ieee_require_asn (info, pp, &control)) + return false; + + /* FIXME: We should now track down name and change its type. */ + } + break; + + case 'R': + if (! ieee_read_reference (info, pp)) + return false; + break; + } + + return true; +} + +/* Read a C++ class definition. This is a pmisc type 80 record of + category 'T'. */ + +static boolean +ieee_read_cxx_class (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + bfd_vma class; + const char *tag; + unsigned long taglen; + struct ieee_tag *it; + PTR dhandle; + debug_field *fields; + unsigned int field_count, field_alloc; + debug_baseclass *baseclasses; + unsigned int baseclasses_count, baseclasses_alloc; + const debug_field *structfields; + struct ieee_method + { + const char *name; + unsigned long namlen; + debug_method_variant *variants; + unsigned count; + unsigned int alloc; + } *methods; + unsigned int methods_count, methods_alloc; + debug_type vptrbase; + boolean ownvptr; + debug_method *dmethods; + + start = *pp; + + if (! ieee_require_asn (info, pp, &class)) + return false; + --count; + + if (! ieee_require_atn65 (info, pp, &tag, &taglen)) + return false; + --count; + + /* Find the C struct with this name. */ + for (it = info->tags; it != NULL; it = it->next) + if (it->name[0] == tag[0] + && strncmp (it->name, tag, taglen) == 0 + && strlen (it->name) == taglen) + break; + if (it == NULL) + { + ieee_error (info, start, "undefined C++ object"); + return false; + } + + dhandle = info->dhandle; + + fields = NULL; + field_count = 0; + field_alloc = 0; + baseclasses = NULL; + baseclasses_count = 0; + baseclasses_alloc = 0; + methods = NULL; + methods_count = 0; + methods_alloc = 0; + vptrbase = DEBUG_TYPE_NULL; + ownvptr = false; + + structfields = debug_get_fields (dhandle, it->type); + + while (count > 0) + { + bfd_vma id; + const bfd_byte *spec_start; + + spec_start = *pp; + + if (! ieee_require_asn (info, pp, &id)) + return false; + --count; + + switch (id) + { + default: + ieee_error (info, spec_start, "unrecognized C++ object spec"); + return false; + + case 'b': + { + bfd_vma flags, cinline; + const char *basename, *fieldname; + unsigned long baselen, fieldlen; + char *basecopy; + debug_type basetype; + bfd_vma bitpos; + boolean virtualp; + enum debug_visibility visibility; + debug_baseclass baseclass; + + /* This represents a base or friend class. */ + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &basename, &baselen) + || ! ieee_require_asn (info, pp, &cinline) + || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)) + return false; + count -= 4; + + /* We have no way of recording friend information, so we + just ignore it. */ + if ((flags & BASEFLAGS_FRIEND) != 0) + break; + + /* I assume that either all of the members of the + baseclass are included in the object, starting at the + beginning of the object, or that none of them are + included. */ + + if ((fieldlen == 0) == (cinline == 0)) + { + ieee_error (info, start, "unsupported C++ object type"); + return false; + } + + basecopy = savestring (basename, baselen); + basetype = debug_find_tagged_type (dhandle, basecopy, + DEBUG_KIND_ILLEGAL); + free (basecopy); + if (basetype == DEBUG_TYPE_NULL) + { + ieee_error (info, start, "C++ base class not defined"); + return false; + } + + if (fieldlen == 0) + bitpos = 0; + else + { + const debug_field *pf; + + if (structfields == NULL) + { + ieee_error (info, start, "C++ object has no fields"); + return false; + } + + for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++) + { + const char *fname; + + fname = debug_get_field_name (dhandle, *pf); + if (fname == NULL) + return false; + if (fname[0] == fieldname[0] + && strncmp (fname, fieldname, fieldlen) == 0 + && strlen (fname) == fieldlen) + break; + } + if (*pf == DEBUG_FIELD_NULL) + { + ieee_error (info, start, + "C++ base class not found in container"); + return false; + } + + bitpos = debug_get_field_bitpos (dhandle, *pf); + } + + if ((flags & BASEFLAGS_VIRTUAL) != 0) + virtualp = true; + else + virtualp = false; + if ((flags & BASEFLAGS_PRIVATE) != 0) + visibility = DEBUG_VISIBILITY_PRIVATE; + else + visibility = DEBUG_VISIBILITY_PUBLIC; + + baseclass = debug_make_baseclass (dhandle, basetype, bitpos, + virtualp, visibility); + if (baseclass == DEBUG_BASECLASS_NULL) + return false; + + if (baseclasses_count + 1 >= baseclasses_alloc) + { + baseclasses_alloc += 10; + baseclasses = ((debug_baseclass *) + xrealloc (baseclasses, + (baseclasses_alloc + * sizeof *baseclasses))); + } + + baseclasses[baseclasses_count] = baseclass; + ++baseclasses_count; + baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL; + } + break; + + case 'd': + { + bfd_vma flags; + const char *fieldname, *mangledname; + unsigned long fieldlen, mangledlen; + char *fieldcopy; + boolean staticp; + debug_type ftype; + const debug_field *pf = NULL; + enum debug_visibility visibility; + debug_field field; + + /* This represents a data member. */ + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen) + || ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen)) + return false; + count -= 3; + + fieldcopy = savestring (fieldname, fieldlen); + + staticp = (flags & CXXFLAGS_STATIC) != 0 ? true : false; + + if (staticp) + { + struct ieee_var *pv, *pvend; + + /* See if we can find a definition for this variable. */ + pv = info->vars.vars; + pvend = pv + info->vars.alloc; + for (; pv < pvend; pv++) + if (pv->namlen == mangledlen + && strncmp (pv->name, mangledname, mangledlen) == 0) + break; + if (pv < pvend) + ftype = pv->type; + else + { + /* This can happen if the variable is never used. */ + ftype = ieee_builtin_type (info, start, + (unsigned int) builtin_void); + } + } + else + { + unsigned int findx; + + if (structfields == NULL) + { + ieee_error (info, start, "C++ object has no fields"); + return false; + } + + for (pf = structfields, findx = 0; + *pf != DEBUG_FIELD_NULL; + pf++, findx++) + { + const char *fname; + + fname = debug_get_field_name (dhandle, *pf); + if (fname == NULL) + return false; + if (fname[0] == mangledname[0] + && strncmp (fname, mangledname, mangledlen) == 0 + && strlen (fname) == mangledlen) + break; + } + if (*pf == DEBUG_FIELD_NULL) + { + ieee_error (info, start, + "C++ data member not found in container"); + return false; + } + + ftype = debug_get_field_type (dhandle, *pf); + + if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER) + { + /* We might need to convert this field into a + reference type later on, so make it an indirect + type. */ + if (it->fslots == NULL) + { + unsigned int fcnt; + const debug_field *pfcnt; + + fcnt = 0; + for (pfcnt = structfields; + *pfcnt != DEBUG_FIELD_NULL; + pfcnt++) + ++fcnt; + it->fslots = ((debug_type *) + xmalloc (fcnt * sizeof *it->fslots)); + memset (it->fslots, 0, + fcnt * sizeof *it->fslots); + } + + if (ftype == DEBUG_TYPE_NULL) + return false; + it->fslots[findx] = ftype; + ftype = debug_make_indirect_type (dhandle, + it->fslots + findx, + (const char *) NULL); + } + } + if (ftype == DEBUG_TYPE_NULL) + return false; + + switch (flags & CXXFLAGS_VISIBILITY) + { + default: + ieee_error (info, start, "unknown C++ visibility"); + return false; + + case CXXFLAGS_VISIBILITY_PUBLIC: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + + case CXXFLAGS_VISIBILITY_PRIVATE: + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + + case CXXFLAGS_VISIBILITY_PROTECTED: + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + } + + if (staticp) + { + char *mangledcopy; + + mangledcopy = savestring (mangledname, mangledlen); + + field = debug_make_static_member (dhandle, fieldcopy, + ftype, mangledcopy, + visibility); + } + else + { + bfd_vma bitpos, bitsize; + + bitpos = debug_get_field_bitpos (dhandle, *pf); + bitsize = debug_get_field_bitsize (dhandle, *pf); + if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1) + { + ieee_error (info, start, "bad C++ field bit pos or size"); + return false; + } + field = debug_make_field (dhandle, fieldcopy, ftype, bitpos, + bitsize, visibility); + } + + if (field == DEBUG_FIELD_NULL) + return false; + + if (field_count + 1 >= field_alloc) + { + field_alloc += 10; + fields = ((debug_field *) + xrealloc (fields, field_alloc * sizeof *fields)); + } + + fields[field_count] = field; + ++field_count; + fields[field_count] = DEBUG_FIELD_NULL; + } + break; + + case 'm': + case 'v': + { + bfd_vma flags, voffset, control; + const char *name, *mangled; + unsigned long namlen, mangledlen; + struct ieee_var *pv, *pvend; + debug_type type; + enum debug_visibility visibility; + boolean constp, volatilep; + char *mangledcopy; + debug_method_variant mv; + struct ieee_method *meth; + unsigned int im; + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &name, &namlen) + || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) + return false; + count -= 3; + if (id != 'v') + voffset = 0; + else + { + if (! ieee_require_asn (info, pp, &voffset)) + return false; + --count; + } + if (! ieee_require_asn (info, pp, &control)) + return false; + --count; + + /* We just ignore the control information. */ + + /* We have no way to represent friend information, so we + just ignore it. */ + if ((flags & CXXFLAGS_FRIEND) != 0) + break; + + /* We should already have seen a type for the function. */ + pv = info->vars.vars; + pvend = pv + info->vars.alloc; + for (; pv < pvend; pv++) + if (pv->namlen == mangledlen + && strncmp (pv->name, mangled, mangledlen) == 0) + break; + + if (pv >= pvend) + { + /* We won't have type information for this function if + it is not included in this file. We don't try to + handle this case. FIXME. */ + type = (debug_make_function_type + (dhandle, + ieee_builtin_type (info, start, + (unsigned int) builtin_void), + (debug_type *) NULL, + false)); + } + else + { + debug_type return_type; + const debug_type *arg_types; + boolean varargs; + + if (debug_get_type_kind (dhandle, pv->type) + != DEBUG_KIND_FUNCTION) + { + ieee_error (info, start, + "bad type for C++ method function"); + return false; + } + + return_type = debug_get_return_type (dhandle, pv->type); + arg_types = debug_get_parameter_types (dhandle, pv->type, + &varargs); + if (return_type == DEBUG_TYPE_NULL || arg_types == NULL) + { + ieee_error (info, start, + "no type information for C++ method function"); + return false; + } + + type = debug_make_method_type (dhandle, return_type, it->type, + (debug_type *) arg_types, + varargs); + } + if (type == DEBUG_TYPE_NULL) + return false; + + switch (flags & CXXFLAGS_VISIBILITY) + { + default: + ieee_error (info, start, "unknown C++ visibility"); + return false; + + case CXXFLAGS_VISIBILITY_PUBLIC: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + + case CXXFLAGS_VISIBILITY_PRIVATE: + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + + case CXXFLAGS_VISIBILITY_PROTECTED: + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + } + + constp = (flags & CXXFLAGS_CONST) != 0 ? true : false; + volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? true : false; + + mangledcopy = savestring (mangled, mangledlen); + + if ((flags & CXXFLAGS_STATIC) != 0) + { + if (id == 'v') + { + ieee_error (info, start, "C++ static virtual method"); + return false; + } + mv = debug_make_static_method_variant (dhandle, mangledcopy, + type, visibility, + constp, volatilep); + } + else + { + debug_type vcontext; + + if (id != 'v') + vcontext = DEBUG_TYPE_NULL; + else + { + /* FIXME: How can we calculate this correctly? */ + vcontext = it->type; + } + mv = debug_make_method_variant (dhandle, mangledcopy, type, + visibility, constp, + volatilep, voffset, + vcontext); + } + if (mv == DEBUG_METHOD_VARIANT_NULL) + return false; + + for (meth = methods, im = 0; im < methods_count; meth++, im++) + if (meth->namlen == namlen + && strncmp (meth->name, name, namlen) == 0) + break; + if (im >= methods_count) + { + if (methods_count >= methods_alloc) + { + methods_alloc += 10; + methods = ((struct ieee_method *) + xrealloc (methods, + methods_alloc * sizeof *methods)); + } + methods[methods_count].name = name; + methods[methods_count].namlen = namlen; + methods[methods_count].variants = NULL; + methods[methods_count].count = 0; + methods[methods_count].alloc = 0; + meth = methods + methods_count; + ++methods_count; + } + + if (meth->count + 1 >= meth->alloc) + { + meth->alloc += 10; + meth->variants = ((debug_method_variant *) + xrealloc (meth->variants, + (meth->alloc + * sizeof *meth->variants))); + } + + meth->variants[meth->count] = mv; + ++meth->count; + meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL; + } + break; + + case 'o': + { + bfd_vma spec; + + /* We have no way to store this information, so we just + ignore it. */ + if (! ieee_require_asn (info, pp, &spec)) + return false; + --count; + if ((spec & 4) != 0) + { + const char *filename; + unsigned long filenamlen; + bfd_vma lineno; + + if (! ieee_require_atn65 (info, pp, &filename, &filenamlen) + || ! ieee_require_asn (info, pp, &lineno)) + return false; + count -= 2; + } + else if ((spec & 8) != 0) + { + const char *mangled; + unsigned long mangledlen; + + if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) + return false; + --count; + } + else + { + ieee_error (info, start, + "unrecognized C++ object overhead spec"); + return false; + } + } + break; + + case 'z': + { + const char *vname, *basename; + unsigned long vnamelen, baselen; + bfd_vma vsize, control; + + /* A virtual table pointer. */ + + if (! ieee_require_atn65 (info, pp, &vname, &vnamelen) + || ! ieee_require_asn (info, pp, &vsize) + || ! ieee_require_atn65 (info, pp, &basename, &baselen) + || ! ieee_require_asn (info, pp, &control)) + return false; + count -= 4; + + /* We just ignore the control number. We don't care what + the virtual table name is. We have no way to store the + virtual table size, and I don't think we care anyhow. */ + + /* FIXME: We can't handle multiple virtual table pointers. */ + + if (baselen == 0) + ownvptr = true; + else + { + char *basecopy; + + basecopy = savestring (basename, baselen); + vptrbase = debug_find_tagged_type (dhandle, basecopy, + DEBUG_KIND_ILLEGAL); + free (basecopy); + if (vptrbase == DEBUG_TYPE_NULL) + { + ieee_error (info, start, "undefined C++ vtable"); + return false; + } + } + } + break; + } + } + + /* Now that we have seen all the method variants, we can call + debug_make_method for each one. */ + + if (methods_count == 0) + dmethods = NULL; + else + { + unsigned int i; + + dmethods = ((debug_method *) + xmalloc ((methods_count + 1) * sizeof *dmethods)); + for (i = 0; i < methods_count; i++) + { + char *namcopy; + + namcopy = savestring (methods[i].name, methods[i].namlen); + dmethods[i] = debug_make_method (dhandle, namcopy, + methods[i].variants); + if (dmethods[i] == DEBUG_METHOD_NULL) + return false; + } + dmethods[i] = DEBUG_METHOD_NULL; + free (methods); + } + + /* The struct type was created as an indirect type pointing at + it->slot. We update it->slot to automatically update all + references to this struct. */ + it->slot = debug_make_object_type (dhandle, + class != 'u', + debug_get_type_size (dhandle, + it->slot), + fields, baseclasses, dmethods, + vptrbase, ownvptr); + if (it->slot == DEBUG_TYPE_NULL) + return false; + + return true; +} + +/* Read C++ default argument value and reference type information. */ + +static boolean +ieee_read_cxx_defaults (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + const char *fnname; + unsigned long fnlen; + bfd_vma defcount; + + start = *pp; + + /* Giving the function name before the argument count is an addendum + to the spec. The function name is demangled, though, so this + record must always refer to the current function. */ + + if (info->blockstack.bsp <= info->blockstack.stack + || info->blockstack.bsp[-1].fnindx == (unsigned int) -1) + { + ieee_error (info, start, "C++ default values not in a function"); + return false; + } + + if (! ieee_require_atn65 (info, pp, &fnname, &fnlen) + || ! ieee_require_asn (info, pp, &defcount)) + return false; + count -= 2; + + while (defcount-- > 0) + { + bfd_vma type, val; + const char *strval; + unsigned long strvallen; + + if (! ieee_require_asn (info, pp, &type)) + return false; + --count; + + switch (type) + { + case 0: + case 4: + break; + + case 1: + case 2: + if (! ieee_require_asn (info, pp, &val)) + return false; + --count; + break; + + case 3: + case 7: + if (! ieee_require_atn65 (info, pp, &strval, &strvallen)) + return false; + --count; + break; + + default: + ieee_error (info, start, "unrecognized C++ default type"); + return false; + } + + /* We have no way to record the default argument values, so we + just ignore them. FIXME. */ + } + + /* Any remaining arguments are indices of parameters that are really + reference type. */ + if (count > 0) + { + PTR dhandle; + debug_type *arg_slots; + + dhandle = info->dhandle; + arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots; + while (count-- > 0) + { + bfd_vma indx; + debug_type target; + + if (! ieee_require_asn (info, pp, &indx)) + return false; + /* The index is 1 based. */ + --indx; + if (arg_slots == NULL + || arg_slots[indx] == DEBUG_TYPE_NULL + || (debug_get_type_kind (dhandle, arg_slots[indx]) + != DEBUG_KIND_POINTER)) + { + ieee_error (info, start, "reference parameter is not a pointer"); + return false; + } + + target = debug_get_target_type (dhandle, arg_slots[indx]); + arg_slots[indx] = debug_make_reference_type (dhandle, target); + if (arg_slots[indx] == DEBUG_TYPE_NULL) + return false; + } + } + + return true; +} + +/* Read a C++ reference definition. */ + +static boolean +ieee_read_reference (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *start; + bfd_vma flags; + const char *class, *name; + unsigned long classlen, namlen; + debug_type *pslot; + debug_type target; + + start = *pp; + + if (! ieee_require_asn (info, pp, &flags)) + return false; + + /* Giving the class name before the member name is in an addendum to + the spec. */ + if (flags == 3) + { + if (! ieee_require_atn65 (info, pp, &class, &classlen)) + return false; + } + + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return false; + + pslot = NULL; + if (flags != 3) + { + int pass; + + /* We search from the last variable indices to the first in + hopes of finding local variables correctly. We search the + local variables on the first pass, and the global variables + on the second. FIXME: This probably won't work in all cases. + On the other hand, I don't know what will. */ + for (pass = 0; pass < 2; pass++) + { + struct ieee_vars *vars; + int i; + struct ieee_var *pv = NULL; + + if (pass == 0) + vars = &info->vars; + else + { + vars = info->global_vars; + if (vars == NULL) + break; + } + + for (i = (int) vars->alloc - 1; i >= 0; i--) + { + boolean found; + + pv = vars->vars + i; + + if (pv->pslot == NULL + || pv->namlen != namlen + || strncmp (pv->name, name, namlen) != 0) + continue; + + found = false; + switch (flags) + { + default: + ieee_error (info, start, + "unrecognized C++ reference type"); + return false; + + case 0: + /* Global variable or function. */ + if (pv->kind == IEEE_GLOBAL + || pv->kind == IEEE_EXTERNAL + || pv->kind == IEEE_FUNCTION) + found = true; + break; + + case 1: + /* Global static variable or function. */ + if (pv->kind == IEEE_STATIC + || pv->kind == IEEE_FUNCTION) + found = true; + break; + + case 2: + /* Local variable. */ + if (pv->kind == IEEE_LOCAL) + found = true; + break; + } + + if (found) + break; + } + + if (i >= 0) + { + pslot = pv->pslot; + break; + } + } + } + else + { + struct ieee_tag *it; + + for (it = info->tags; it != NULL; it = it->next) + { + if (it->name[0] == class[0] + && strncmp (it->name, class, classlen) == 0 + && strlen (it->name) == classlen) + { + if (it->fslots != NULL) + { + const debug_field *pf; + unsigned int findx; + + pf = debug_get_fields (info->dhandle, it->type); + if (pf == NULL) + { + ieee_error (info, start, + "C++ reference in class with no fields"); + return false; + } + + for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++) + { + const char *fname; + + fname = debug_get_field_name (info->dhandle, *pf); + if (fname == NULL) + return false; + if (strncmp (fname, name, namlen) == 0 + && strlen (fname) == namlen) + { + pslot = it->fslots + findx; + break; + } + } + } + + break; + } + } + } + + if (pslot == NULL) + { + ieee_error (info, start, "C++ reference not found"); + return false; + } + + /* We allocated the type of the object as an indirect type pointing + to *pslot, which we can now update to be a reference type. */ + if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER) + { + ieee_error (info, start, "C++ reference is not pointer"); + return false; + } + + target = debug_get_target_type (info->dhandle, *pslot); + *pslot = debug_make_reference_type (info->dhandle, target); + if (*pslot == DEBUG_TYPE_NULL) + return false; + + return true; +} + +/* Require an ASN record. */ + +static boolean +ieee_require_asn (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + const bfd_byte *start; + ieee_record_enum_type c; + bfd_vma varindx; + + start = *pp; + + c = (ieee_record_enum_type) **pp; + if (c != ieee_e2_first_byte_enum) + { + ieee_error (info, start, "missing required ASN"); + return false; + } + ++*pp; + + c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); + if (c != ieee_asn_record_enum) + { + ieee_error (info, start, "missing required ASN"); + return false; + } + ++*pp; + + /* Just ignore the variable index. */ + if (! ieee_read_number (info, pp, &varindx)) + return false; + + return ieee_read_expression (info, pp, pv); +} + +/* Require an ATN65 record. */ + +static boolean +ieee_require_atn65 (info, pp, pname, pnamlen) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; +{ + const bfd_byte *start; + ieee_record_enum_type c; + bfd_vma name_indx, type_indx, atn_code; + + start = *pp; + + c = (ieee_record_enum_type) **pp; + if (c != ieee_at_record_enum) + { + ieee_error (info, start, "missing required ATN65"); + return false; + } + ++*pp; + + c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); + if (c != ieee_atn_record_enum) + { + ieee_error (info, start, "missing required ATN65"); + return false; + } + ++*pp; + + if (! ieee_read_number (info, pp, &name_indx) + || ! ieee_read_number (info, pp, &type_indx) + || ! ieee_read_number (info, pp, &atn_code)) + return false; + + /* Just ignore name_indx. */ + + if (type_indx != 0 || atn_code != 65) + { + ieee_error (info, start, "bad ATN65 record"); + return false; + } + + return ieee_read_id (info, pp, pname, pnamlen); +} + +/* Convert a register number in IEEE debugging information into a + generic register number. */ + +static int +ieee_regno_to_genreg (abfd, r) + bfd *abfd; + int r; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + /* For some reasons stabs adds 2 to the floating point register + numbers. */ + if (r >= 16) + r += 2; + break; + + case bfd_arch_i960: + /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and + 32 to 35 for fp0 to fp3. */ + --r; + break; + + default: + break; + } + + return r; +} + +/* Convert a generic register number to an IEEE specific one. */ + +static int +ieee_genreg_to_regno (abfd, r) + bfd *abfd; + int r; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + /* For some reason stabs add 2 to the floating point register + numbers. */ + if (r >= 18) + r -= 2; + break; + + case bfd_arch_i960: + /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and + 32 to 35 for fp0 to fp3. */ + ++r; + break; + + default: + break; + } + + return r; +} + +/* These routines build IEEE debugging information out of the generic + debugging information. */ + +/* We build the IEEE debugging information byte by byte. Rather than + waste time copying data around, we use a linked list of buffers to + hold the data. */ + +#define IEEE_BUFSIZE (490) + +struct ieee_buf +{ + /* Next buffer. */ + struct ieee_buf *next; + /* Number of data bytes in this buffer. */ + unsigned int c; + /* Bytes. */ + bfd_byte buf[IEEE_BUFSIZE]; +}; + +/* A list of buffers. */ + +struct ieee_buflist +{ + /* Head of list. */ + struct ieee_buf *head; + /* Tail--last buffer on list. */ + struct ieee_buf *tail; +}; + +/* In order to generate the BB11 blocks required by the HP emulator, + we keep track of ranges of addresses which correspond to a given + compilation unit. */ + +struct ieee_range +{ + /* Next range. */ + struct ieee_range *next; + /* Low address. */ + bfd_vma low; + /* High address. */ + bfd_vma high; +}; + +/* This structure holds information for a class on the type stack. */ + +struct ieee_type_class +{ + /* The name index in the debugging information. */ + unsigned int indx; + /* The pmisc records for the class. */ + struct ieee_buflist pmiscbuf; + /* The number of pmisc records. */ + unsigned int pmisccount; + /* The name of the class holding the virtual table, if not this + class. */ + const char *vclass; + /* Whether this class holds its own virtual table. */ + boolean ownvptr; + /* The largest virtual table offset seen so far. */ + bfd_vma voffset; + /* The current method. */ + const char *method; + /* Additional pmisc records used to record fields of reference type. */ + struct ieee_buflist refs; +}; + +/* This is how we store types for the writing routines. Most types + are simply represented by a type index. */ + +struct ieee_write_type +{ + /* Type index. */ + unsigned int indx; + /* The size of the type, if known. */ + unsigned int size; + /* The name of the type, if any. */ + const char *name; + /* If this is a function or method type, we build the type here, and + only add it to the output buffers if we need it. */ + struct ieee_buflist fndef; + /* If this is a struct, this is where the struct definition is + built. */ + struct ieee_buflist strdef; + /* If this is a class, this is where the class information is built. */ + struct ieee_type_class *classdef; + /* Whether the type is unsigned. */ + unsigned int unsignedp : 1; + /* Whether this is a reference type. */ + unsigned int referencep : 1; + /* Whether this is in the local type block. */ + unsigned int localp : 1; + /* Whether this is a duplicate struct definition which we are + ignoring. */ + unsigned int ignorep : 1; +}; + +/* This is the type stack used by the debug writing routines. FIXME: + We could generate more efficient output if we remembered when we + have output a particular type before. */ + +struct ieee_type_stack +{ + /* Next entry on stack. */ + struct ieee_type_stack *next; + /* Type information. */ + struct ieee_write_type type; +}; + +/* This is a list of associations between a name and some types. + These are used for typedefs and tags. */ + +struct ieee_name_type +{ + /* Next type for this name. */ + struct ieee_name_type *next; + /* ID number. For a typedef, this is the index of the type to which + this name is typedefed. */ + unsigned int id; + /* Type. */ + struct ieee_write_type type; + /* If this is a tag which has not yet been defined, this is the + kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */ + enum debug_type_kind kind; +}; + +/* We use a hash table to associate names and types. */ + +struct ieee_name_type_hash_table +{ + struct bfd_hash_table root; +}; + +struct ieee_name_type_hash_entry +{ + struct bfd_hash_entry root; + /* Information for this name. */ + struct ieee_name_type *types; +}; + +/* This is a list of enums. */ + +struct ieee_defined_enum +{ + /* Next enum. */ + struct ieee_defined_enum *next; + /* Type index. */ + unsigned int indx; + /* Whether this enum has been defined. */ + boolean defined; + /* Tag. */ + const char *tag; + /* Names. */ + const char **names; + /* Values. */ + bfd_signed_vma *vals; +}; + +/* We keep a list of modified versions of types, so that we don't + output them more than once. */ + +struct ieee_modified_type +{ + /* Pointer to this type. */ + unsigned int pointer; + /* Function with unknown arguments returning this type. */ + unsigned int function; + /* Const version of this type. */ + unsigned int const_qualified; + /* Volatile version of this type. */ + unsigned int volatile_qualified; + /* List of arrays of this type of various bounds. */ + struct ieee_modified_array_type *arrays; +}; + +/* A list of arrays bounds. */ + +struct ieee_modified_array_type +{ + /* Next array bounds. */ + struct ieee_modified_array_type *next; + /* Type index with these bounds. */ + unsigned int indx; + /* Low bound. */ + bfd_signed_vma low; + /* High bound. */ + bfd_signed_vma high; +}; + +/* This is a list of pending function parameter information. We don't + output them until we see the first block. */ + +struct ieee_pending_parm +{ + /* Next pending parameter. */ + struct ieee_pending_parm *next; + /* Name. */ + const char *name; + /* Type index. */ + unsigned int type; + /* Whether the type is a reference. */ + boolean referencep; + /* Kind. */ + enum debug_parm_kind kind; + /* Value. */ + bfd_vma val; +}; + +/* This is the handle passed down by debug_write. */ + +struct ieee_handle +{ + /* BFD we are writing to. */ + bfd *abfd; + /* Whether we got an error in a subroutine called via traverse or + map_over_sections. */ + boolean error; + /* Current data buffer list. */ + struct ieee_buflist *current; + /* Current data buffer. */ + struct ieee_buf *curbuf; + /* Filename of current compilation unit. */ + const char *filename; + /* Module name of current compilation unit. */ + const char *modname; + /* List of buffer for global types. */ + struct ieee_buflist global_types; + /* List of finished data buffers. */ + struct ieee_buflist data; + /* List of buffers for typedefs in the current compilation unit. */ + struct ieee_buflist types; + /* List of buffers for variables and functions in the current + compilation unit. */ + struct ieee_buflist vars; + /* List of buffers for C++ class definitions in the current + compilation unit. */ + struct ieee_buflist cxx; + /* List of buffers for line numbers in the current compilation unit. */ + struct ieee_buflist linenos; + /* Ranges for the current compilation unit. */ + struct ieee_range *ranges; + /* Ranges for all debugging information. */ + struct ieee_range *global_ranges; + /* Nested pending ranges. */ + struct ieee_range *pending_ranges; + /* Type stack. */ + struct ieee_type_stack *type_stack; + /* Next unallocated type index. */ + unsigned int type_indx; + /* Next unallocated name index. */ + unsigned int name_indx; + /* Typedefs. */ + struct ieee_name_type_hash_table typedefs; + /* Tags. */ + struct ieee_name_type_hash_table tags; + /* Enums. */ + struct ieee_defined_enum *enums; + /* Modified versions of types. */ + struct ieee_modified_type *modified; + /* Number of entries allocated in modified. */ + unsigned int modified_alloc; + /* 4 byte complex type. */ + unsigned int complex_float_index; + /* 8 byte complex type. */ + unsigned int complex_double_index; + /* The depth of block nesting. This is 0 outside a function, and 1 + just after start_function is called. */ + unsigned int block_depth; + /* The name of the current function. */ + const char *fnname; + /* List of buffers for the type of the function we are currently + writing out. */ + struct ieee_buflist fntype; + /* List of buffers for the parameters of the function we are + currently writing out. */ + struct ieee_buflist fnargs; + /* Number of arguments written to fnargs. */ + unsigned int fnargcount; + /* Pending function parameters. */ + struct ieee_pending_parm *pending_parms; + /* Current line number filename. */ + const char *lineno_filename; + /* Line number name index. */ + unsigned int lineno_name_indx; + /* Filename of pending line number. */ + const char *pending_lineno_filename; + /* Pending line number. */ + unsigned long pending_lineno; + /* Address of pending line number. */ + bfd_vma pending_lineno_addr; + /* Highest address seen at end of procedure. */ + bfd_vma highaddr; +}; + +static boolean ieee_init_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *)); +static boolean ieee_change_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *)); +static boolean ieee_append_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *, + struct ieee_buflist *)); +static boolean ieee_real_write_byte PARAMS ((struct ieee_handle *, int)); +static boolean ieee_write_2bytes PARAMS ((struct ieee_handle *, int)); +static boolean ieee_write_number PARAMS ((struct ieee_handle *, bfd_vma)); +static boolean ieee_write_id PARAMS ((struct ieee_handle *, const char *)); +static boolean ieee_write_asn + PARAMS ((struct ieee_handle *, unsigned int, bfd_vma)); +static boolean ieee_write_atn65 + PARAMS ((struct ieee_handle *, unsigned int, const char *)); +static boolean ieee_push_type + PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean, + boolean)); +static unsigned int ieee_pop_type PARAMS ((struct ieee_handle *)); +static void ieee_pop_unused_type PARAMS ((struct ieee_handle *)); +static unsigned int ieee_pop_type_used + PARAMS ((struct ieee_handle *, boolean)); +static boolean ieee_add_range + PARAMS ((struct ieee_handle *, boolean, bfd_vma, bfd_vma)); +static boolean ieee_start_range PARAMS ((struct ieee_handle *, bfd_vma)); +static boolean ieee_end_range PARAMS ((struct ieee_handle *, bfd_vma)); +static boolean ieee_define_type + PARAMS ((struct ieee_handle *, unsigned int, boolean, boolean)); +static boolean ieee_define_named_type + PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int, + boolean, boolean, struct ieee_buflist *)); +static struct ieee_modified_type *ieee_get_modified_info + PARAMS ((struct ieee_handle *, unsigned int)); +static struct bfd_hash_entry *ieee_name_type_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean ieee_write_undefined_tag + PARAMS ((struct ieee_name_type_hash_entry *, PTR)); +static boolean ieee_finish_compilation_unit PARAMS ((struct ieee_handle *)); +static void ieee_add_bb11_blocks PARAMS ((bfd *, asection *, PTR)); +static boolean ieee_add_bb11 + PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma)); +static boolean ieee_output_pending_parms PARAMS ((struct ieee_handle *)); +static unsigned int ieee_vis_to_flags PARAMS ((enum debug_visibility)); +static boolean ieee_class_method_var + PARAMS ((struct ieee_handle *, const char *, enum debug_visibility, boolean, + boolean, boolean, bfd_vma, boolean)); + +static boolean ieee_start_compilation_unit PARAMS ((PTR, const char *)); +static boolean ieee_start_source PARAMS ((PTR, const char *)); +static boolean ieee_empty_type PARAMS ((PTR)); +static boolean ieee_void_type PARAMS ((PTR)); +static boolean ieee_int_type PARAMS ((PTR, unsigned int, boolean)); +static boolean ieee_float_type PARAMS ((PTR, unsigned int)); +static boolean ieee_complex_type PARAMS ((PTR, unsigned int)); +static boolean ieee_bool_type PARAMS ((PTR, unsigned int)); +static boolean ieee_enum_type + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); +static boolean ieee_pointer_type PARAMS ((PTR)); +static boolean ieee_function_type PARAMS ((PTR, int, boolean)); +static boolean ieee_reference_type PARAMS ((PTR)); +static boolean ieee_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); +static boolean ieee_array_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean)); +static boolean ieee_set_type PARAMS ((PTR, boolean)); +static boolean ieee_offset_type PARAMS ((PTR)); +static boolean ieee_method_type PARAMS ((PTR, boolean, int, boolean)); +static boolean ieee_const_type PARAMS ((PTR)); +static boolean ieee_volatile_type PARAMS ((PTR)); +static boolean ieee_start_struct_type + PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int)); +static boolean ieee_struct_field + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); +static boolean ieee_end_struct_type PARAMS ((PTR)); +static boolean ieee_start_class_type + PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean, + boolean)); +static boolean ieee_class_static_member + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); +static boolean ieee_class_baseclass + PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility)); +static boolean ieee_class_start_method PARAMS ((PTR, const char *)); +static boolean ieee_class_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean, + bfd_vma, boolean)); +static boolean ieee_class_static_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean)); +static boolean ieee_class_end_method PARAMS ((PTR)); +static boolean ieee_end_class_type PARAMS ((PTR)); +static boolean ieee_typedef_type PARAMS ((PTR, const char *)); +static boolean ieee_tag_type + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); +static boolean ieee_typdef PARAMS ((PTR, const char *)); +static boolean ieee_tag PARAMS ((PTR, const char *)); +static boolean ieee_int_constant PARAMS ((PTR, const char *, bfd_vma)); +static boolean ieee_float_constant PARAMS ((PTR, const char *, double)); +static boolean ieee_typed_constant PARAMS ((PTR, const char *, bfd_vma)); +static boolean ieee_variable + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); +static boolean ieee_start_function PARAMS ((PTR, const char *, boolean)); +static boolean ieee_function_parameter + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); +static boolean ieee_start_block PARAMS ((PTR, bfd_vma)); +static boolean ieee_end_block PARAMS ((PTR, bfd_vma)); +static boolean ieee_end_function PARAMS ((PTR)); +static boolean ieee_lineno + PARAMS ((PTR, const char *, unsigned long, bfd_vma)); + +static const struct debug_write_fns ieee_fns = +{ + ieee_start_compilation_unit, + ieee_start_source, + ieee_empty_type, + ieee_void_type, + ieee_int_type, + ieee_float_type, + ieee_complex_type, + ieee_bool_type, + ieee_enum_type, + ieee_pointer_type, + ieee_function_type, + ieee_reference_type, + ieee_range_type, + ieee_array_type, + ieee_set_type, + ieee_offset_type, + ieee_method_type, + ieee_const_type, + ieee_volatile_type, + ieee_start_struct_type, + ieee_struct_field, + ieee_end_struct_type, + ieee_start_class_type, + ieee_class_static_member, + ieee_class_baseclass, + ieee_class_start_method, + ieee_class_method_variant, + ieee_class_static_method_variant, + ieee_class_end_method, + ieee_end_class_type, + ieee_typedef_type, + ieee_tag_type, + ieee_typdef, + ieee_tag, + ieee_int_constant, + ieee_float_constant, + ieee_typed_constant, + ieee_variable, + ieee_start_function, + ieee_function_parameter, + ieee_start_block, + ieee_end_block, + ieee_end_function, + ieee_lineno +}; + +/* Initialize a buffer to be empty. */ + +/*ARGSUSED*/ +static boolean +ieee_init_buffer (info, buflist) + struct ieee_handle *info; + struct ieee_buflist *buflist; +{ + buflist->head = NULL; + buflist->tail = NULL; + return true; +} + +/* See whether a buffer list has any data. */ + +#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL) + +/* Change the current buffer to a specified buffer chain. */ + +static boolean +ieee_change_buffer (info, buflist) + struct ieee_handle *info; + struct ieee_buflist *buflist; +{ + if (buflist->head == NULL) + { + struct ieee_buf *buf; + + buf = (struct ieee_buf *) xmalloc (sizeof *buf); + buf->next = NULL; + buf->c = 0; + buflist->head = buf; + buflist->tail = buf; + } + + info->current = buflist; + info->curbuf = buflist->tail; + + return true; +} + +/* Append a buffer chain. */ + +/*ARGSUSED*/ +static boolean +ieee_append_buffer (info, mainbuf, newbuf) + struct ieee_handle *info; + struct ieee_buflist *mainbuf; + struct ieee_buflist *newbuf; +{ + if (newbuf->head != NULL) + { + if (mainbuf->head == NULL) + mainbuf->head = newbuf->head; + else + mainbuf->tail->next = newbuf->head; + mainbuf->tail = newbuf->tail; + } + return true; +} + +/* Write a byte into the buffer. We use a macro for speed and a + function for the complex cases. */ + +#define ieee_write_byte(info, b) \ + ((info)->curbuf->c < IEEE_BUFSIZE \ + ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), true) \ + : ieee_real_write_byte ((info), (b))) + +static boolean +ieee_real_write_byte (info, b) + struct ieee_handle *info; + int b; +{ + if (info->curbuf->c >= IEEE_BUFSIZE) + { + struct ieee_buf *n; + + n = (struct ieee_buf *) xmalloc (sizeof *n); + n->next = NULL; + n->c = 0; + if (info->current->head == NULL) + info->current->head = n; + else + info->current->tail->next = n; + info->current->tail = n; + info->curbuf = n; + } + + info->curbuf->buf[info->curbuf->c] = b; + ++info->curbuf->c; + + return true; +} + +/* Write out two bytes. */ + +static boolean +ieee_write_2bytes (info, i) + struct ieee_handle *info; + int i; +{ + return (ieee_write_byte (info, i >> 8) + && ieee_write_byte (info, i & 0xff)); +} + +/* Write out an integer. */ + +static boolean +ieee_write_number (info, v) + struct ieee_handle *info; + bfd_vma v; +{ + bfd_vma t; + bfd_byte ab[20]; + bfd_byte *p; + unsigned int c; + + if (v <= (bfd_vma) ieee_number_end_enum) + return ieee_write_byte (info, (int) v); + + t = v; + p = ab + sizeof ab; + while (t != 0) + { + *--p = t & 0xff; + t >>= 8; + } + c = (ab + 20) - p; + + if (c > (unsigned int) (ieee_number_repeat_end_enum + - ieee_number_repeat_start_enum)) + { + fprintf (stderr, "IEEE numeric overflow: 0x"); + fprintf_vma (stderr, v); + fprintf (stderr, "\n"); + return false; + } + + if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c)) + return false; + for (; c > 0; --c, ++p) + { + if (! ieee_write_byte (info, *p)) + return false; + } + + return true; +} + +/* Write out a string. */ + +static boolean +ieee_write_id (info, s) + struct ieee_handle *info; + const char *s; +{ + unsigned int len; + + len = strlen (s); + if (len <= 0x7f) + { + if (! ieee_write_byte (info, len)) + return false; + } + else if (len <= 0xff) + { + if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum) + || ! ieee_write_byte (info, len)) + return false; + } + else if (len <= 0xffff) + { + if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum) + || ! ieee_write_2bytes (info, len)) + return false; + } + else + { + fprintf (stderr, "IEEE string length overflow: %u\n", len); + return false; + } + + for (; *s != '\0'; s++) + if (! ieee_write_byte (info, *s)) + return false; + + return true; +} + +/* Write out an ASN record. */ + +static boolean +ieee_write_asn (info, indx, val) + struct ieee_handle *info; + unsigned int indx; + bfd_vma val; +{ + return (ieee_write_2bytes (info, (int) ieee_asn_record_enum) + && ieee_write_number (info, indx) + && ieee_write_number (info, val)); +} + +/* Write out an ATN65 record. */ + +static boolean +ieee_write_atn65 (info, indx, s) + struct ieee_handle *info; + unsigned int indx; + const char *s; +{ + return (ieee_write_2bytes (info, (int) ieee_atn_record_enum) + && ieee_write_number (info, indx) + && ieee_write_number (info, 0) + && ieee_write_number (info, 65) + && ieee_write_id (info, s)); +} + +/* Push a type index onto the type stack. */ + +static boolean +ieee_push_type (info, indx, size, unsignedp, localp) + struct ieee_handle *info; + unsigned int indx; + unsigned int size; + boolean unsignedp; + boolean localp; +{ + struct ieee_type_stack *ts; + + ts = (struct ieee_type_stack *) xmalloc (sizeof *ts); + memset (ts, 0, sizeof *ts); + + ts->type.indx = indx; + ts->type.size = size; + ts->type.unsignedp = unsignedp; + ts->type.localp = localp; + + ts->next = info->type_stack; + info->type_stack = ts; + + return true; +} + +/* Pop a type index off the type stack. */ + +static unsigned int +ieee_pop_type (info) + struct ieee_handle *info; +{ + return ieee_pop_type_used (info, true); +} + +/* Pop an unused type index off the type stack. */ + +static void +ieee_pop_unused_type (info) + struct ieee_handle *info; +{ + (void) ieee_pop_type_used (info, false); +} + +/* Pop a used or unused type index off the type stack. */ + +static unsigned int +ieee_pop_type_used (info, used) + struct ieee_handle *info; + boolean used; +{ + struct ieee_type_stack *ts; + unsigned int ret; + + ts = info->type_stack; + assert (ts != NULL); + + /* If this is a function type, and we need it, we need to append the + actual definition to the typedef block now. */ + if (used && ! ieee_buffer_emptyp (&ts->type.fndef)) + { + struct ieee_buflist *buflist; + + if (ts->type.localp) + { + /* Make sure we have started the types block. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + } + buflist = &info->types; + } + else + { + /* Make sure we started the global type block. */ + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return false; + } + buflist = &info->global_types; + } + + if (! ieee_append_buffer (info, buflist, &ts->type.fndef)) + return false; + } + + ret = ts->type.indx; + info->type_stack = ts->next; + free (ts); + return ret; +} + +/* Add a range of bytes included in the current compilation unit. */ + +static boolean +ieee_add_range (info, global, low, high) + struct ieee_handle *info; + boolean global; + bfd_vma low; + bfd_vma high; +{ + struct ieee_range **plist, *r, **pr; + + if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high) + return true; + + if (global) + plist = &info->global_ranges; + else + plist = &info->ranges; + + for (r = *plist; r != NULL; r = r->next) + { + if (high >= r->low && low <= r->high) + { + /* The new range overlaps r. */ + if (low < r->low) + r->low = low; + if (high > r->high) + r->high = high; + pr = &r->next; + while (*pr != NULL && (*pr)->low <= r->high) + { + struct ieee_range *n; + + if ((*pr)->high > r->high) + r->high = (*pr)->high; + n = (*pr)->next; + free (*pr); + *pr = n; + } + return true; + } + } + + r = (struct ieee_range *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + + r->low = low; + r->high = high; + + /* Store the ranges sorted by address. */ + for (pr = plist; *pr != NULL; pr = &(*pr)->next) + if ((*pr)->low > high) + break; + r->next = *pr; + *pr = r; + + return true; +} + +/* Start a new range for which we only have the low address. */ + +static boolean +ieee_start_range (info, low) + struct ieee_handle *info; + bfd_vma low; +{ + struct ieee_range *r; + + r = (struct ieee_range *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + r->low = low; + r->next = info->pending_ranges; + info->pending_ranges = r; + return true; +} + +/* Finish a range started by ieee_start_range. */ + +static boolean +ieee_end_range (info, high) + struct ieee_handle *info; + bfd_vma high; +{ + struct ieee_range *r; + bfd_vma low; + + assert (info->pending_ranges != NULL); + r = info->pending_ranges; + low = r->low; + info->pending_ranges = r->next; + free (r); + return ieee_add_range (info, false, low, high); +} + +/* Start defining a type. */ + +static boolean +ieee_define_type (info, size, unsignedp, localp) + struct ieee_handle *info; + unsigned int size; + boolean unsignedp; + boolean localp; +{ + return ieee_define_named_type (info, (const char *) NULL, + (unsigned int) -1, size, unsignedp, + localp, (struct ieee_buflist *) NULL); +} + +/* Start defining a named type. */ + +static boolean +ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist) + struct ieee_handle *info; + const char *name; + unsigned int indx; + unsigned int size; + boolean unsignedp; + boolean localp; + struct ieee_buflist *buflist; +{ + unsigned int type_indx; + unsigned int name_indx; + + if (indx != (unsigned int) -1) + type_indx = indx; + else + { + type_indx = info->type_indx; + ++info->type_indx; + } + + name_indx = info->name_indx; + ++info->name_indx; + + if (name == NULL) + name = ""; + + /* If we were given a buffer, use it; otherwise, use either the + local or the global type information, and make sure that the type + block is started. */ + if (buflist != NULL) + { + if (! ieee_change_buffer (info, buflist)) + return false; + } + else if (localp) + { + if (! ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types)) + return false; + } + else + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + } + } + else + { + if (! ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types)) + return false; + } + else + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return false; + } + } + + /* Push the new type on the type stack, write out an NN record, and + write out the start of a TY record. The caller will then finish + the TY record. */ + if (! ieee_push_type (info, type_indx, size, unsignedp, localp)) + return false; + + return (ieee_write_byte (info, (int) ieee_nn_record) + && ieee_write_number (info, name_indx) + && ieee_write_id (info, name) + && ieee_write_byte (info, (int) ieee_ty_record_enum) + && ieee_write_number (info, type_indx) + && ieee_write_byte (info, 0xce) + && ieee_write_number (info, name_indx)); +} + +/* Get an entry to the list of modified versions of a type. */ + +static struct ieee_modified_type * +ieee_get_modified_info (info, indx) + struct ieee_handle *info; + unsigned int indx; +{ + if (indx >= info->modified_alloc) + { + unsigned int nalloc; + + nalloc = info->modified_alloc; + if (nalloc == 0) + nalloc = 16; + while (indx >= nalloc) + nalloc *= 2; + info->modified = ((struct ieee_modified_type *) + xrealloc (info->modified, + nalloc * sizeof *info->modified)); + memset (info->modified + info->modified_alloc, 0, + (nalloc - info->modified_alloc) * sizeof *info->modified); + info->modified_alloc = nalloc; + } + + return info->modified + indx; +} + +/* Routines for the hash table mapping names to types. */ + +/* Initialize an entry in the hash table. */ + +static struct bfd_hash_entry * +ieee_name_type_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ieee_name_type_hash_entry *ret = + (struct ieee_name_type_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct ieee_name_type_hash_entry *) + bfd_hash_allocate (table, sizeof *ret)); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ieee_name_type_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret) + { + /* Set local fields. */ + ret->types = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in the hash table. */ + +#define ieee_name_type_hash_lookup(table, string, create, copy) \ + ((struct ieee_name_type_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Traverse the hash table. */ + +#define ieee_name_type_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ + (info))) + +/* The general routine to write out IEEE debugging information. */ + +boolean +write_ieee_debugging_info (abfd, dhandle) + bfd *abfd; + PTR dhandle; +{ + struct ieee_handle info; + asection *s; + const char *err; + struct ieee_buf *b; + + memset (&info, 0, sizeof info); + info.abfd = abfd; + info.type_indx = 256; + info.name_indx = 32; + + if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc) + || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc)) + return false; + + if (! ieee_init_buffer (&info, &info.global_types) + || ! ieee_init_buffer (&info, &info.data) + || ! ieee_init_buffer (&info, &info.types) + || ! ieee_init_buffer (&info, &info.vars) + || ! ieee_init_buffer (&info, &info.cxx) + || ! ieee_init_buffer (&info, &info.linenos) + || ! ieee_init_buffer (&info, &info.fntype) + || ! ieee_init_buffer (&info, &info.fnargs)) + return false; + + if (! debug_write (dhandle, &ieee_fns, (PTR) &info)) + return false; + + if (info.filename != NULL) + { + if (! ieee_finish_compilation_unit (&info)) + return false; + } + + /* Put any undefined tags in the global typedef information. */ + info.error = false; + ieee_name_type_hash_traverse (&info.tags, + ieee_write_undefined_tag, + (PTR) &info); + if (info.error) + return false; + + /* Prepend the global typedef information to the other data. */ + if (! ieee_buffer_emptyp (&info.global_types)) + { + /* The HP debugger seems to have a bug in which it ignores the + last entry in the global types, so we add a dummy entry. */ + if (! ieee_change_buffer (&info, &info.global_types) + || ! ieee_write_byte (&info, (int) ieee_nn_record) + || ! ieee_write_number (&info, info.name_indx) + || ! ieee_write_id (&info, "") + || ! ieee_write_byte (&info, (int) ieee_ty_record_enum) + || ! ieee_write_number (&info, info.type_indx) + || ! ieee_write_byte (&info, 0xce) + || ! ieee_write_number (&info, info.name_indx) + || ! ieee_write_number (&info, 'P') + || ! ieee_write_number (&info, (int) builtin_void + 32) + || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) + return false; + + if (! ieee_append_buffer (&info, &info.global_types, &info.data)) + return false; + info.data = info.global_types; + } + + /* Make sure that we have declare BB11 blocks for each range in the + file. They are added to info->vars. */ + info.error = false; + if (! ieee_init_buffer (&info, &info.vars)) + return false; + bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info); + if (info.error) + return false; + if (! ieee_buffer_emptyp (&info.vars)) + { + if (! ieee_change_buffer (&info, &info.vars) + || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) + return false; + + if (! ieee_append_buffer (&info, &info.data, &info.vars)) + return false; + } + + /* Now all the data is in info.data. Write it out to the BFD. We + normally would need to worry about whether all the other sections + are set up yet, but the IEEE backend will handle this particular + case correctly regardless. */ + if (ieee_buffer_emptyp (&info.data)) + { + /* There is no debugging information. */ + return true; + } + err = NULL; + s = bfd_make_section (abfd, ".debug"); + if (s == NULL) + err = "bfd_make_section"; + if (err == NULL) + { + if (! bfd_set_section_flags (abfd, s, SEC_DEBUGGING | SEC_HAS_CONTENTS)) + err = "bfd_set_section_flags"; + } + if (err == NULL) + { + bfd_size_type size; + + size = 0; + for (b = info.data.head; b != NULL; b = b->next) + size += b->c; + if (! bfd_set_section_size (abfd, s, size)) + err = "bfd_set_section_size"; + } + if (err == NULL) + { + file_ptr offset; + + offset = 0; + for (b = info.data.head; b != NULL; b = b->next) + { + if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c)) + { + err = "bfd_set_section_contents"; + break; + } + offset += b->c; + } + } + + if (err != NULL) + { + fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err, + bfd_errmsg (bfd_get_error ())); + return false; + } + + bfd_hash_table_free (&info.typedefs.root); + bfd_hash_table_free (&info.tags.root); + + return true; +} + +/* Write out information for an undefined tag. This is called via + ieee_name_type_hash_traverse. */ + +static boolean +ieee_write_undefined_tag (h, p) + struct ieee_name_type_hash_entry *h; + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_name_type *nt; + + for (nt = h->types; nt != NULL; nt = nt->next) + { + unsigned int name_indx; + char code; + + if (nt->kind == DEBUG_KIND_ILLEGAL) + continue; + + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + { + info->error = true; + return false; + } + } + else + { + if (! ieee_change_buffer (info, &info->global_types)) + { + info->error = true; + return false; + } + } + + name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_id (info, nt->type.name) + || ! ieee_write_byte (info, (int) ieee_ty_record_enum) + || ! ieee_write_number (info, nt->type.indx) + || ! ieee_write_byte (info, 0xce) + || ! ieee_write_number (info, name_indx)) + { + info->error = true; + return false; + } + + switch (nt->kind) + { + default: + abort (); + info->error = true; + return false; + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_CLASS: + code = 'S'; + break; + case DEBUG_KIND_UNION: + case DEBUG_KIND_UNION_CLASS: + code = 'U'; + break; + case DEBUG_KIND_ENUM: + code = 'E'; + break; + } + if (! ieee_write_number (info, code) + || ! ieee_write_number (info, 0)) + { + info->error = true; + return false; + } + } + + return true; +} + +/* Start writing out information for a compilation unit. */ + +static boolean +ieee_start_compilation_unit (p, filename) + PTR p; + const char *filename; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *modname; + char *c, *s; + unsigned int nindx; + + if (info->filename != NULL) + { + if (! ieee_finish_compilation_unit (info)) + return false; + } + + info->filename = filename; + modname = strrchr (filename, '/'); + if (modname != NULL) + ++modname; + else + { + modname = strrchr (filename, '\\'); + if (modname != NULL) + ++modname; + else + modname = filename; + } + c = xstrdup (modname); + s = strrchr (c, '.'); + if (s != NULL) + *s = '\0'; + info->modname = c; + + if (! ieee_init_buffer (info, &info->types) + || ! ieee_init_buffer (info, &info->vars) + || ! ieee_init_buffer (info, &info->cxx) + || ! ieee_init_buffer (info, &info->linenos)) + return false; + info->ranges = NULL; + + /* Always include a BB1 and a BB3 block. That is what the output of + the MRI linker seems to look like. */ + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 3) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + + return true; +} + +/* Finish up a compilation unit. */ + +static boolean +ieee_finish_compilation_unit (info) + struct ieee_handle *info; +{ + struct ieee_range *r; + + if (! ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + } + + if (! ieee_buffer_emptyp (&info->cxx)) + { + /* Append any C++ information to the global function and + variable information. */ + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return false; + + /* We put the pmisc records in a dummy procedure, just as the + MRI compiler does. */ + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 6) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "__XRYCPP") + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, info->highaddr - 1) + || ! ieee_append_buffer (info, &info->vars, &info->cxx) + || ! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, info->highaddr - 1)) + return false; + } + + if (! ieee_buffer_emptyp (&info->vars)) + { + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + } + + if (info->pending_lineno_filename != NULL) + { + /* Force out the pending line number. */ + if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1)) + return false; + } + if (! ieee_buffer_emptyp (&info->linenos)) + { + if (! ieee_change_buffer (info, &info->linenos) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + if (strcmp (info->filename, info->lineno_filename) != 0) + { + /* We were not in the main file. We just closed the + included line number block, and now we must close the + main line number block. */ + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + } + } + + if (! ieee_append_buffer (info, &info->data, &info->types) + || ! ieee_append_buffer (info, &info->data, &info->vars) + || ! ieee_append_buffer (info, &info->data, &info->linenos)) + return false; + + /* Build BB10/BB11 blocks based on the ranges we recorded. */ + if (! ieee_change_buffer (info, &info->data)) + return false; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 10) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "GNU objcopy")) + return false; + + for (r = info->ranges; r != NULL; r = r->next) + { + bfd_vma low, high; + asection *s; + int kind; + + low = r->low; + high = r->high; + + /* Find the section corresponding to this range. */ + for (s = info->abfd->sections; s != NULL; s = s->next) + { + if (bfd_get_section_vma (info->abfd, s) <= low + && high <= (bfd_get_section_vma (info->abfd, s) + + bfd_section_size (info->abfd, s))) + break; + } + + if (s == NULL) + { + /* Just ignore this range. */ + continue; + } + + /* Coalesce ranges if it seems reasonable. */ + while (r->next != NULL + && high + 0x1000 >= r->next->low + && (r->next->high + <= (bfd_get_section_vma (info->abfd, s) + + bfd_section_size (info->abfd, s)))) + { + r = r->next; + high = r->high; + } + + if ((s->flags & SEC_CODE) != 0) + kind = 1; + else if ((s->flags & SEC_READONLY) != 0) + kind = 3; + else + kind = 2; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 11) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, kind) + || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE) + || ! ieee_write_number (info, low) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, high - low)) + return false; + + /* Add this range to the list of global ranges. */ + if (! ieee_add_range (info, true, low, high)) + return false; + } + + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + + return true; +} + +/* Add BB11 blocks describing each range that we have not already + described. */ + +static void +ieee_add_bb11_blocks (abfd, sec, data) + bfd *abfd; + asection *sec; + PTR data; +{ + struct ieee_handle *info = (struct ieee_handle *) data; + bfd_vma low, high; + struct ieee_range *r; + + low = bfd_get_section_vma (abfd, sec); + high = low + bfd_section_size (abfd, sec); + + /* Find the first range at or after this section. The ranges are + sorted by address. */ + for (r = info->global_ranges; r != NULL; r = r->next) + if (r->high > low) + break; + + while (low < high) + { + if (r == NULL || r->low >= high) + { + if (! ieee_add_bb11 (info, sec, low, high)) + info->error = true; + return; + } + + if (low < r->low + && r->low - low > 0x100) + { + if (! ieee_add_bb11 (info, sec, low, r->low)) + { + info->error = true; + return; + } + } + low = r->high; + + r = r->next; + } +} + +/* Add a single BB11 block for a range. We add it to info->vars. */ + +static boolean +ieee_add_bb11 (info, sec, low, high) + struct ieee_handle *info; + asection *sec; + bfd_vma low; + bfd_vma high; +{ + int kind; + + if (! ieee_buffer_emptyp (&info->vars)) + { + if (! ieee_change_buffer (info, &info->vars)) + return false; + } + else + { + const char *filename, *modname; + char *c, *s; + + /* Start the enclosing BB10 block. */ + filename = bfd_get_filename (info->abfd); + modname = strrchr (filename, '/'); + if (modname != NULL) + ++modname; + else + { + modname = strrchr (filename, '\\'); + if (modname != NULL) + ++modname; + else + modname = filename; + } + c = xstrdup (modname); + s = strrchr (c, '.'); + if (s != NULL) + *s = '\0'; + + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 10) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, c) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "GNU objcopy")) + return false; + + free (c); + } + + if ((sec->flags & SEC_CODE) != 0) + kind = 1; + else if ((sec->flags & SEC_READONLY) != 0) + kind = 3; + else + kind = 2; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 11) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, kind) + || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE) + || ! ieee_write_number (info, low) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, high - low)) + return false; + + return true; +} + +/* Start recording information from a particular source file. This is + used to record which file defined which types, variables, etc. It + is not used for line numbers, since the lineno entry point passes + down the file name anyhow. IEEE debugging information doesn't seem + to store this information anywhere. */ + +/*ARGSUSED*/ +static boolean +ieee_start_source (p, filename) + PTR p; + const char *filename; +{ + return true; +} + +/* Make an empty type. */ + +static boolean +ieee_empty_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_push_type (info, (int) builtin_unknown, 0, false, false); +} + +/* Make a void type. */ + +static boolean +ieee_void_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_push_type (info, (int) builtin_void, 0, false, false); +} + +/* Make an integer type. */ + +static boolean +ieee_int_type (p, size, unsignedp) + PTR p; + unsigned int size; + boolean unsignedp; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int indx; + + switch (size) + { + case 1: + indx = (int) builtin_signed_char; + break; + case 2: + indx = (int) builtin_signed_short_int; + break; + case 4: + indx = (int) builtin_signed_long; + break; + case 8: + indx = (int) builtin_signed_long_long; + break; + default: + fprintf (stderr, "IEEE unsupported integer type size %u\n", size); + return false; + } + + if (unsignedp) + ++indx; + + return ieee_push_type (info, indx, size, unsignedp, false); +} + +/* Make a floating point type. */ + +static boolean +ieee_float_type (p, size) + PTR p; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int indx; + + switch (size) + { + case 4: + indx = (int) builtin_float; + break; + case 8: + indx = (int) builtin_double; + break; + case 12: + /* FIXME: This size really depends upon the processor. */ + indx = (int) builtin_long_double; + break; + case 16: + indx = (int) builtin_long_long_double; + break; + default: + fprintf (stderr, "IEEE unsupported float type size %u\n", size); + return false; + } + + return ieee_push_type (info, indx, size, false, false); +} + +/* Make a complex type. */ + +static boolean +ieee_complex_type (p, size) + PTR p; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + char code; + + switch (size) + { + case 4: + if (info->complex_float_index != 0) + return ieee_push_type (info, info->complex_float_index, size * 2, + false, false); + code = 'c'; + break; + case 12: + case 16: + /* These cases can be output by gcc -gstabs. Outputting the + wrong type is better than crashing. */ + case 8: + if (info->complex_double_index != 0) + return ieee_push_type (info, info->complex_double_index, size * 2, + false, false); + code = 'd'; + break; + default: + fprintf (stderr, "IEEE unsupported complex type size %u\n", size); + return false; + } + + /* FIXME: I don't know what the string is for. */ + if (! ieee_define_type (info, size * 2, false, false) + || ! ieee_write_number (info, code) + || ! ieee_write_id (info, "")) + return false; + + if (size == 4) + info->complex_float_index = info->type_stack->type.indx; + else + info->complex_double_index = info->type_stack->type.indx; + + return true; +} + +/* Make a boolean type. IEEE doesn't support these, so we just make + an integer type instead. */ + +static boolean +ieee_bool_type (p, size) + PTR p; + unsigned int size; +{ + return ieee_int_type (p, size, true); +} + +/* Make an enumeration. */ + +static boolean +ieee_enum_type (p, tag, names, vals) + PTR p; + const char *tag; + const char **names; + bfd_signed_vma *vals; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_defined_enum *e; + boolean localp, simple; + unsigned int indx; + int i = 0; + + localp = false; + indx = (unsigned int) -1; + for (e = info->enums; e != NULL; e = e->next) + { + if (tag == NULL) + { + if (e->tag != NULL) + continue; + } + else + { + if (e->tag == NULL + || tag[0] != e->tag[0] + || strcmp (tag, e->tag) != 0) + continue; + } + + if (! e->defined) + { + /* This enum tag has been seen but not defined. */ + indx = e->indx; + break; + } + + if (names != NULL && e->names != NULL) + { + for (i = 0; names[i] != NULL && e->names[i] != NULL; i++) + { + if (names[i][0] != e->names[i][0] + || vals[i] != e->vals[i] + || strcmp (names[i], e->names[i]) != 0) + break; + } + } + + if ((names == NULL && e->names == NULL) + || (names != NULL + && e->names != NULL + && names[i] == NULL + && e->names[i] == NULL)) + { + /* We've seen this enum before. */ + return ieee_push_type (info, e->indx, 0, true, false); + } + + if (tag != NULL) + { + /* We've already seen an enum of the same name, so we must make + sure to output this one locally. */ + localp = true; + break; + } + } + + /* If this is a simple enumeration, in which the values start at 0 + and always increment by 1, we can use type E. Otherwise we must + use type N. */ + + simple = true; + if (names != NULL) + { + for (i = 0; names[i] != NULL; i++) + { + if (vals[i] != i) + { + simple = false; + break; + } + } + } + + if (! ieee_define_named_type (info, tag, indx, 0, true, localp, + (struct ieee_buflist *) NULL) + || ! ieee_write_number (info, simple ? 'E' : 'N')) + return false; + if (simple) + { + /* FIXME: This is supposed to be the enumeration size, but we + don't store that. */ + if (! ieee_write_number (info, 4)) + return false; + } + if (names != NULL) + { + for (i = 0; names[i] != NULL; i++) + { + if (! ieee_write_id (info, names[i])) + return false; + if (! simple) + { + if (! ieee_write_number (info, vals[i])) + return false; + } + } + } + + if (! localp) + { + if (indx == (unsigned int) -1) + { + e = (struct ieee_defined_enum *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + e->indx = info->type_stack->type.indx; + e->tag = tag; + + e->next = info->enums; + info->enums = e; + } + + e->names = names; + e->vals = vals; + e->defined = true; + } + + return true; +} + +/* Make a pointer type. */ + +static boolean +ieee_pointer_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + /* A pointer to a simple builtin type can be obtained by adding 32. + FIXME: Will this be a short pointer, and will that matter? */ + if (indx < 32) + return ieee_push_type (info, indx + 32, 0, true, false); + + if (! localp) + { + m = ieee_get_modified_info (p, indx); + if (m == NULL) + return false; + + /* FIXME: The size should depend upon the architecture. */ + if (m->pointer > 0) + return ieee_push_type (info, m->pointer, 4, true, false); + } + + if (! ieee_define_type (info, 4, true, localp) + || ! ieee_write_number (info, 'P') + || ! ieee_write_number (info, indx)) + return false; + + if (! localp) + m->pointer = info->type_stack->type.indx; + + return true; +} + +/* Make a function type. This will be called for a method, but we + don't want to actually add it to the type table in that case. We + handle this by defining the type in a private buffer, and only + adding that buffer to the typedef block if we are going to use it. */ + +static boolean +ieee_function_type (p, argcount, varargs) + PTR p; + int argcount; + boolean varargs; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean localp; + unsigned int *args = NULL; + int i; + unsigned int retindx; + struct ieee_buflist fndef; + struct ieee_modified_type *m; + + localp = false; + + if (argcount > 0) + { + args = (unsigned int *) xmalloc (argcount * sizeof *args); + for (i = argcount - 1; i >= 0; i--) + { + if (info->type_stack->type.localp) + localp = true; + args[i] = ieee_pop_type (info); + } + } + else if (argcount < 0) + varargs = false; + + if (info->type_stack->type.localp) + localp = true; + retindx = ieee_pop_type (info); + + m = NULL; + if (argcount < 0 && ! localp) + { + m = ieee_get_modified_info (p, retindx); + if (m == NULL) + return false; + + if (m->function > 0) + return ieee_push_type (info, m->function, 0, true, false); + } + + /* An attribute of 0x41 means that the frame and push mask are + unknown. */ + if (! ieee_init_buffer (info, &fndef) + || ! ieee_define_named_type (info, (const char *) NULL, + (unsigned int) -1, 0, true, localp, + &fndef) + || ! ieee_write_number (info, 'x') + || ! ieee_write_number (info, 0x41) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, retindx) + || ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0))) + return false; + if (argcount > 0) + { + for (i = 0; i < argcount; i++) + if (! ieee_write_number (info, args[i])) + return false; + free (args); + } + if (varargs) + { + /* A varargs function is represented by writing out the last + argument as type void *, although this makes little sense. */ + if (! ieee_write_number (info, (bfd_vma) builtin_void + 32)) + return false; + } + + if (! ieee_write_number (info, 0)) + return false; + + /* We wrote the information into fndef, in case we don't need it. + It will be appended to info->types by ieee_pop_type. */ + info->type_stack->type.fndef = fndef; + + if (m != NULL) + m->function = info->type_stack->type.indx; + + return true; +} + +/* Make a reference type. */ + +static boolean +ieee_reference_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* IEEE appears to record a normal pointer type, and then use a + pmisc record to indicate that it is really a reference. */ + + if (! ieee_pointer_type (p)) + return false; + info->type_stack->type.referencep = true; + return true; +} + +/* Make a range type. */ + +static boolean +ieee_range_type (p, low, high) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + boolean unsignedp, localp; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + ieee_pop_unused_type (info); + return (ieee_define_type (info, size, unsignedp, localp) + && ieee_write_number (info, 'R') + && ieee_write_number (info, (bfd_vma) low) + && ieee_write_number (info, (bfd_vma) high) + && ieee_write_number (info, unsignedp ? 0 : 1) + && ieee_write_number (info, size)); +} + +/* Make an array type. */ + +/*ARGSUSED*/ +static boolean +ieee_array_type (p, low, high, stringp) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; + boolean stringp; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int eleindx; + boolean localp; + unsigned int size; + struct ieee_modified_type *m = NULL; + struct ieee_modified_array_type *a; + + /* IEEE does not store the range, so we just ignore it. */ + ieee_pop_unused_type (info); + localp = info->type_stack->type.localp; + size = info->type_stack->type.size; + eleindx = ieee_pop_type (info); + + /* If we don't know the range, treat the size as exactly one + element. */ + if (low < high) + size *= (high - low) + 1; + + if (! localp) + { + m = ieee_get_modified_info (info, eleindx); + if (m == NULL) + return false; + + for (a = m->arrays; a != NULL; a = a->next) + { + if (a->low == low && a->high == high) + return ieee_push_type (info, a->indx, size, false, false); + } + } + + if (! ieee_define_type (info, size, false, localp) + || ! ieee_write_number (info, low == 0 ? 'Z' : 'C') + || ! ieee_write_number (info, eleindx)) + return false; + if (low != 0) + { + if (! ieee_write_number (info, low)) + return false; + } + + if (! ieee_write_number (info, high + 1)) + return false; + + if (! localp) + { + a = (struct ieee_modified_array_type *) xmalloc (sizeof *a); + memset (a, 0, sizeof *a); + + a->indx = info->type_stack->type.indx; + a->low = low; + a->high = high; + + a->next = m->arrays; + m->arrays = a; + } + + return true; +} + +/* Make a set type. */ + +static boolean +ieee_set_type (p, bitstringp) + PTR p; + boolean bitstringp; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean localp; + unsigned int eleindx; + + localp = info->type_stack->type.localp; + eleindx = ieee_pop_type (info); + + /* FIXME: We don't know the size, so we just use 4. */ + + return (ieee_define_type (info, 0, true, localp) + && ieee_write_number (info, 's') + && ieee_write_number (info, 4) + && ieee_write_number (info, eleindx)); +} + +/* Make an offset type. */ + +static boolean +ieee_offset_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int targetindx, baseindx; + + targetindx = ieee_pop_type (info); + baseindx = ieee_pop_type (info); + + /* FIXME: The MRI C++ compiler does not appear to generate any + useful type information about an offset type. It just records a + pointer to member as an integer. The MRI/HP IEEE spec does + describe a pmisc record which can be used for a pointer to + member. Unfortunately, it does not describe the target type, + which seems pretty important. I'm going to punt this for now. */ + + return ieee_int_type (p, 4, true); +} + +/* Make a method type. */ + +static boolean +ieee_method_type (p, domain, argcount, varargs) + PTR p; + boolean domain; + int argcount; + boolean varargs; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a + method, but the definition is incomplete. We just output an 'x' + type. */ + + if (domain) + ieee_pop_unused_type (info); + + return ieee_function_type (p, argcount, varargs); +} + +/* Make a const qualified type. */ + +static boolean +ieee_const_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + boolean unsignedp, localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (! localp) + { + m = ieee_get_modified_info (info, indx); + if (m == NULL) + return false; + + if (m->const_qualified > 0) + return ieee_push_type (info, m->const_qualified, size, unsignedp, + false); + } + + if (! ieee_define_type (info, size, unsignedp, localp) + || ! ieee_write_number (info, 'n') + || ! ieee_write_number (info, 1) + || ! ieee_write_number (info, indx)) + return false; + + if (! localp) + m->const_qualified = info->type_stack->type.indx; + + return true; +} + +/* Make a volatile qualified type. */ + +static boolean +ieee_volatile_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + boolean unsignedp, localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (! localp) + { + m = ieee_get_modified_info (info, indx); + if (m == NULL) + return false; + + if (m->volatile_qualified > 0) + return ieee_push_type (info, m->volatile_qualified, size, unsignedp, + false); + } + + if (! ieee_define_type (info, size, unsignedp, localp) + || ! ieee_write_number (info, 'n') + || ! ieee_write_number (info, 2) + || ! ieee_write_number (info, indx)) + return false; + + if (! localp) + m->volatile_qualified = info->type_stack->type.indx; + + return true; +} + +/* Convert an enum debug_visibility into a CXXFLAGS value. */ + +static unsigned int +ieee_vis_to_flags (visibility) + enum debug_visibility visibility; +{ + switch (visibility) + { + default: + abort (); + case DEBUG_VISIBILITY_PUBLIC: + return CXXFLAGS_VISIBILITY_PUBLIC; + case DEBUG_VISIBILITY_PRIVATE: + return CXXFLAGS_VISIBILITY_PRIVATE; + case DEBUG_VISIBILITY_PROTECTED: + return CXXFLAGS_VISIBILITY_PROTECTED; + } + /*NOTREACHED*/ +} + +/* Start defining a struct type. We build it in the strdef field on + the stack, to avoid confusing type definitions required by the + fields with the struct type itself. */ + +static boolean +ieee_start_struct_type (p, tag, id, structp, size) + PTR p; + const char *tag; + unsigned int id; + boolean structp; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean localp, ignorep; + boolean copy; + char ab[20]; + const char *look; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt, *ntlook; + struct ieee_buflist strdef; + + localp = false; + ignorep = false; + + /* We need to create a tag for internal use even if we don't want + one for external use. This will let us refer to an anonymous + struct. */ + if (tag != NULL) + { + look = tag; + copy = false; + } + else + { + sprintf (ab, "__anon%u", id); + look = ab; + copy = true; + } + + /* If we already have references to the tag, we must use the + existing type index. */ + h = ieee_name_type_hash_lookup (&info->tags, look, true, copy); + if (h == NULL) + return false; + + nt = NULL; + for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next) + { + if (ntlook->id == id) + nt = ntlook; + else if (! ntlook->type.localp) + { + /* We are creating a duplicate definition of a globally + defined tag. Force it to be local to avoid + confusion. */ + localp = true; + } + } + + if (nt != NULL) + { + assert (localp == nt->type.localp); + if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp) + { + /* We've already seen a global definition of the type. + Ignore this new definition. */ + ignorep = true; + } + } + else + { + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + nt->id = id; + nt->type.name = h->root.string; + nt->next = h->types; + h->types = nt; + nt->type.indx = info->type_indx; + ++info->type_indx; + } + + nt->kind = DEBUG_KIND_ILLEGAL; + + if (! ieee_init_buffer (info, &strdef) + || ! ieee_define_named_type (info, tag, nt->type.indx, size, true, + localp, &strdef) + || ! ieee_write_number (info, structp ? 'S' : 'U') + || ! ieee_write_number (info, size)) + return false; + + if (! ignorep) + { + const char *hold; + + /* We never want nt->type.name to be NULL. We want the rest of + the type to be the object set up on the type stack; it will + have a NULL name if tag is NULL. */ + hold = nt->type.name; + nt->type = info->type_stack->type; + nt->type.name = hold; + } + + info->type_stack->type.name = tag; + info->type_stack->type.strdef = strdef; + info->type_stack->type.ignorep = ignorep; + + return true; +} + +/* Add a field to a struct. */ + +static boolean +ieee_struct_field (p, name, bitpos, bitsize, visibility) + PTR p; + const char *name; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + boolean unsignedp; + boolean referencep; + boolean localp; + unsigned int indx; + bfd_vma offset; + + assert (info->type_stack != NULL + && info->type_stack->next != NULL + && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); + + /* If we are ignoring this struct definition, just pop and ignore + the type. */ + if (info->type_stack->next->type.ignorep) + { + ieee_pop_unused_type (info); + return true; + } + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + referencep = info->type_stack->type.referencep; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (localp) + info->type_stack->type.localp = true; + + if (info->type_stack->type.classdef != NULL) + { + unsigned int flags; + unsigned int nindx; + + /* This is a class. We must add a description of this field to + the class records we are building. */ + + flags = ieee_vis_to_flags (visibility); + nindx = info->type_stack->type.classdef->indx; + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'd') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, name) + || ! ieee_write_atn65 (info, nindx, name)) + return false; + info->type_stack->type.classdef->pmisccount += 4; + + if (referencep) + { + unsigned int nindx; + + /* We need to output a record recording that this field is + really of reference type. We put this on the refs field + of classdef, so that it can be appended to the C++ + records after the class is defined. */ + + nindx = info->name_indx; + ++info->name_indx; + + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->refs) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 4) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, 3) + || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name) + || ! ieee_write_atn65 (info, nindx, name)) + return false; + } + } + + /* If the bitsize doesn't match the expected size, we need to output + a bitfield type. */ + if (size == 0 || bitsize == 0 || bitsize == size * 8) + offset = bitpos / 8; + else + { + if (! ieee_define_type (info, 0, unsignedp, + info->type_stack->type.localp) + || ! ieee_write_number (info, 'g') + || ! ieee_write_number (info, unsignedp ? 0 : 1) + || ! ieee_write_number (info, bitsize) + || ! ieee_write_number (info, indx)) + return false; + indx = ieee_pop_type (info); + offset = bitpos; + } + + /* Switch to the struct we are building in order to output this + field definition. */ + return (ieee_change_buffer (info, &info->type_stack->type.strdef) + && ieee_write_id (info, name) + && ieee_write_number (info, indx) + && ieee_write_number (info, offset)); +} + +/* Finish up a struct type. */ + +static boolean +ieee_end_struct_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_buflist *pb; + + assert (info->type_stack != NULL + && ! ieee_buffer_emptyp (&info->type_stack->type.strdef)); + + /* If we were ignoring this struct definition because it was a + duplicate defintion, just through away whatever bytes we have + accumulated. Leave the type on the stack. */ + if (info->type_stack->type.ignorep) + return true; + + /* If this is not a duplicate definition of this tag, then localp + will be false, and we can put it in the global type block. + FIXME: We should avoid outputting duplicate definitions which are + the same. */ + if (! info->type_stack->type.localp) + { + /* Make sure we have started the global type block. */ + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return false; + } + pb = &info->global_types; + } + else + { + /* Make sure we have started the types block. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + } + pb = &info->types; + } + + /* Append the struct definition to the types. */ + if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef) + || ! ieee_init_buffer (info, &info->type_stack->type.strdef)) + return false; + + /* Leave the struct on the type stack. */ + + return true; +} + +/* Start a class type. */ + +static boolean +ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr) + PTR p; + const char *tag; + unsigned int id; + boolean structp; + unsigned int size; + boolean vptr; + boolean ownvptr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *vclass; + struct ieee_buflist pmiscbuf; + unsigned int indx; + struct ieee_type_class *classdef; + + /* A C++ class is output as a C++ struct along with a set of pmisc + records describing the class. */ + + /* We need to have a name so that we can associate the struct and + the class. */ + if (tag == NULL) + { + char *t; + + t = (char *) xmalloc (20); + sprintf (t, "__anon%u", id); + tag = t; + } + + /* We can't write out the virtual table information until we have + finished the class, because we don't know the virtual table size. + We get the size from the largest voffset we see. */ + vclass = NULL; + if (vptr && ! ownvptr) + { + vclass = info->type_stack->type.name; + assert (vclass != NULL); + /* We don't call ieee_pop_unused_type, since the class should + get defined. */ + (void) ieee_pop_type (info); + } + + if (! ieee_start_struct_type (p, tag, id, structp, size)) + return false; + + indx = info->name_indx; + ++info->name_indx; + + /* We write out pmisc records into the classdef field. We will + write out the pmisc start after we know the number of records we + need. */ + if (! ieee_init_buffer (info, &pmiscbuf) + || ! ieee_change_buffer (info, &pmiscbuf) + || ! ieee_write_asn (info, indx, 'T') + || ! ieee_write_asn (info, indx, structp ? 'o' : 'u') + || ! ieee_write_atn65 (info, indx, tag)) + return false; + + classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef); + memset (classdef, 0, sizeof *classdef); + + classdef->indx = indx; + classdef->pmiscbuf = pmiscbuf; + classdef->pmisccount = 3; + classdef->vclass = vclass; + classdef->ownvptr = ownvptr; + + info->type_stack->type.classdef = classdef; + + return true; +} + +/* Add a static member to a class. */ + +static boolean +ieee_class_static_member (p, name, physname, visibility) + PTR p; + const char *name; + const char *physname; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int flags; + unsigned int nindx; + + /* We don't care about the type. Hopefully there will be a call to + ieee_variable declaring the physical name and the type, since + that is where an IEEE consumer must get the type. */ + ieee_pop_unused_type (info); + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL); + + flags = ieee_vis_to_flags (visibility); + flags |= CXXFLAGS_STATIC; + + nindx = info->type_stack->type.classdef->indx; + + if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'd') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, name) + || ! ieee_write_atn65 (info, nindx, physname)) + return false; + info->type_stack->type.classdef->pmisccount += 4; + + return true; +} + +/* Add a base class to a class. */ + +static boolean +ieee_class_baseclass (p, bitpos, virtual, visibility) + PTR p; + bfd_vma bitpos; + boolean virtual; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *bname; + boolean localp; + unsigned int bindx; + char *fname; + unsigned int flags; + unsigned int nindx; + + assert (info->type_stack != NULL + && info->type_stack->type.name != NULL + && info->type_stack->next != NULL + && info->type_stack->next->type.classdef != NULL + && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); + + bname = info->type_stack->type.name; + localp = info->type_stack->type.localp; + bindx = ieee_pop_type (info); + + /* We are currently defining both a struct and a class. We must + write out a field definition in the struct which holds the base + class. The stabs debugging reader will create a field named + _vb$CLASS for a virtual base class, so we just use that. FIXME: + we should not depend upon a detail of stabs debugging. */ + if (virtual) + { + fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$"); + sprintf (fname, "_vb$%s", bname); + flags = BASEFLAGS_VIRTUAL; + } + else + { + if (localp) + info->type_stack->type.localp = true; + + fname = (char *) xmalloc (strlen (bname) + sizeof "_b$"); + sprintf (fname, "_b$%s", bname); + + if (! ieee_change_buffer (info, &info->type_stack->type.strdef) + || ! ieee_write_id (info, fname) + || ! ieee_write_number (info, bindx) + || ! ieee_write_number (info, bitpos / 8)) + return false; + flags = 0; + } + + if (visibility == DEBUG_VISIBILITY_PRIVATE) + flags |= BASEFLAGS_PRIVATE; + + nindx = info->type_stack->type.classdef->indx; + + if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'b') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, bname) + || ! ieee_write_asn (info, nindx, 0) + || ! ieee_write_atn65 (info, nindx, fname)) + return false; + info->type_stack->type.classdef->pmisccount += 5; + + free (fname); + + return true; +} + +/* Start building a method for a class. */ + +static boolean +ieee_class_start_method (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method == NULL); + + info->type_stack->type.classdef->method = name; + + return true; +} + +/* Define a new method variant, either static or not. */ + +static boolean +ieee_class_method_var (info, physname, visibility, staticp, constp, + volatilep, voffset, context) + struct ieee_handle *info; + const char *physname; + enum debug_visibility visibility; + boolean staticp; + boolean constp; + boolean volatilep; + bfd_vma voffset; + boolean context; +{ + unsigned int flags; + unsigned int nindx; + boolean virtual; + + /* We don't need the type of the method. An IEEE consumer which + wants the type must track down the function by the physical name + and get the type from that. */ + ieee_pop_unused_type (info); + + /* We don't use the context. FIXME: We probably ought to use it to + adjust the voffset somehow, but I don't really know how. */ + if (context) + ieee_pop_unused_type (info); + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method != NULL); + + flags = ieee_vis_to_flags (visibility); + + /* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR, + CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */ + + if (staticp) + flags |= CXXFLAGS_STATIC; + if (constp) + flags |= CXXFLAGS_CONST; + if (volatilep) + flags |= CXXFLAGS_VOLATILE; + + nindx = info->type_stack->type.classdef->indx; + + virtual = context || voffset > 0; + + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, virtual ? 'v' : 'm') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, + info->type_stack->type.classdef->method) + || ! ieee_write_atn65 (info, nindx, physname)) + return false; + + if (virtual) + { + if (voffset > info->type_stack->type.classdef->voffset) + info->type_stack->type.classdef->voffset = voffset; + if (! ieee_write_asn (info, nindx, voffset)) + return false; + ++info->type_stack->type.classdef->pmisccount; + } + + if (! ieee_write_asn (info, nindx, 0)) + return false; + + info->type_stack->type.classdef->pmisccount += 5; + + return true; +} + +/* Define a new method variant. */ + +static boolean +ieee_class_method_variant (p, physname, visibility, constp, volatilep, + voffset, context) + PTR p; + const char *physname; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; + bfd_vma voffset; + boolean context; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_class_method_var (info, physname, visibility, false, constp, + volatilep, voffset, context); +} + +/* Define a new static method variant. */ + +static boolean +ieee_class_static_method_variant (p, physname, visibility, constp, volatilep) + PTR p; + const char *physname; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_class_method_var (info, physname, visibility, true, constp, + volatilep, 0, false); +} + +/* Finish up a method. */ + +static boolean +ieee_class_end_method (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method != NULL); + + info->type_stack->type.classdef->method = NULL; + + return true; +} + +/* Finish up a class. */ + +static boolean +ieee_end_class_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int nindx; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL); + + /* If we were ignoring this class definition because it was a + duplicate definition, just through away whatever bytes we have + accumulated. Leave the type on the stack. */ + if (info->type_stack->type.ignorep) + return true; + + nindx = info->type_stack->type.classdef->indx; + + /* If we have a virtual table, we can write out the information now. */ + if (info->type_stack->type.classdef->vclass != NULL + || info->type_stack->type.classdef->ownvptr) + { + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'z') + || ! ieee_write_atn65 (info, nindx, "") + || ! ieee_write_asn (info, nindx, + info->type_stack->type.classdef->voffset)) + return false; + if (info->type_stack->type.classdef->ownvptr) + { + if (! ieee_write_atn65 (info, nindx, "")) + return false; + } + else + { + if (! ieee_write_atn65 (info, nindx, + info->type_stack->type.classdef->vclass)) + return false; + } + if (! ieee_write_asn (info, nindx, 0)) + return false; + info->type_stack->type.classdef->pmisccount += 5; + } + + /* Now that we know the number of pmisc records, we can write out + the atn62 which starts the pmisc records, and append them to the + C++ buffers. */ + + if (! ieee_change_buffer (info, &info->cxx) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, + info->type_stack->type.classdef->pmisccount)) + return false; + + if (! ieee_append_buffer (info, &info->cxx, + &info->type_stack->type.classdef->pmiscbuf)) + return false; + if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs)) + { + if (! ieee_append_buffer (info, &info->cxx, + &info->type_stack->type.classdef->refs)) + return false; + } + + return ieee_end_struct_type (p); +} + +/* Push a previously seen typedef onto the type stack. */ + +static boolean +ieee_typedef_type (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + h = ieee_name_type_hash_lookup (&info->typedefs, name, false, false); + + /* h should never be NULL, since that would imply that the generic + debugging code has asked for a typedef which it has not yet + defined. */ + assert (h != NULL); + + /* We always use the most recently defined type for this name, which + will be the first one on the list. */ + + nt = h->types; + if (! ieee_push_type (info, nt->type.indx, nt->type.size, + nt->type.unsignedp, nt->type.localp)) + return false; + + /* Copy over any other type information we may have. */ + info->type_stack->type = nt->type; + + return true; +} + +/* Push a tagged type onto the type stack. */ + +static boolean +ieee_tag_type (p, name, id, kind) + PTR p; + const char *name; + unsigned int id; + enum debug_type_kind kind; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean localp; + boolean copy; + char ab[20]; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + if (kind == DEBUG_KIND_ENUM) + { + struct ieee_defined_enum *e; + + if (name == NULL) + abort (); + for (e = info->enums; e != NULL; e = e->next) + if (e->tag != NULL && strcmp (e->tag, name) == 0) + return ieee_push_type (info, e->indx, 0, true, false); + + e = (struct ieee_defined_enum *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + + e->indx = info->type_indx; + ++info->type_indx; + e->tag = name; + e->defined = false; + + e->next = info->enums; + info->enums = e; + + return ieee_push_type (info, e->indx, 0, true, false); + } + + localp = false; + + copy = false; + if (name == NULL) + { + sprintf (ab, "__anon%u", id); + name = ab; + copy = true; + } + + h = ieee_name_type_hash_lookup (&info->tags, name, true, copy); + if (h == NULL) + return false; + + for (nt = h->types; nt != NULL; nt = nt->next) + { + if (nt->id == id) + { + if (! ieee_push_type (info, nt->type.indx, nt->type.size, + nt->type.unsignedp, nt->type.localp)) + return false; + /* Copy over any other type information we may have. */ + info->type_stack->type = nt->type; + return true; + } + + if (! nt->type.localp) + { + /* This is a duplicate of a global type, so it must be + local. */ + localp = true; + } + } + + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + + nt->id = id; + nt->type.name = h->root.string; + nt->type.indx = info->type_indx; + nt->type.localp = localp; + ++info->type_indx; + nt->kind = kind; + + nt->next = h->types; + h->types = nt; + + if (! ieee_push_type (info, nt->type.indx, 0, false, localp)) + return false; + + info->type_stack->type.name = h->root.string; + + return true; +} + +/* Output a typedef. */ + +static boolean +ieee_typdef (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_write_type type; + unsigned int indx; + boolean found; + boolean localp; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + type = info->type_stack->type; + indx = type.indx; + + /* If this is a simple builtin type using a builtin name, we don't + want to output the typedef itself. We also want to change the + type index to correspond to the name being used. We recognize + names used in stabs debugging output even if they don't exactly + correspond to the names used for the IEEE builtin types. */ + found = false; + if (indx <= (unsigned int) builtin_bcd_float) + { + switch ((enum builtin_types) indx) + { + default: + break; + + case builtin_void: + if (strcmp (name, "void") == 0) + found = true; + break; + + case builtin_signed_char: + case builtin_char: + if (strcmp (name, "signed char") == 0) + { + indx = (unsigned int) builtin_signed_char; + found = true; + } + else if (strcmp (name, "char") == 0) + { + indx = (unsigned int) builtin_char; + found = true; + } + break; + + case builtin_unsigned_char: + if (strcmp (name, "unsigned char") == 0) + found = true; + break; + + case builtin_signed_short_int: + case builtin_short: + case builtin_short_int: + case builtin_signed_short: + if (strcmp (name, "signed short int") == 0) + { + indx = (unsigned int) builtin_signed_short_int; + found = true; + } + else if (strcmp (name, "short") == 0) + { + indx = (unsigned int) builtin_short; + found = true; + } + else if (strcmp (name, "short int") == 0) + { + indx = (unsigned int) builtin_short_int; + found = true; + } + else if (strcmp (name, "signed short") == 0) + { + indx = (unsigned int) builtin_signed_short; + found = true; + } + break; + + case builtin_unsigned_short_int: + case builtin_unsigned_short: + if (strcmp (name, "unsigned short int") == 0 + || strcmp (name, "short unsigned int") == 0) + { + indx = builtin_unsigned_short_int; + found = true; + } + else if (strcmp (name, "unsigned short") == 0) + { + indx = builtin_unsigned_short; + found = true; + } + break; + + case builtin_signed_long: + case builtin_int: /* FIXME: Size depends upon architecture. */ + case builtin_long: + if (strcmp (name, "signed long") == 0) + { + indx = builtin_signed_long; + found = true; + } + else if (strcmp (name, "int") == 0) + { + indx = builtin_int; + found = true; + } + else if (strcmp (name, "long") == 0 + || strcmp (name, "long int") == 0) + { + indx = builtin_long; + found = true; + } + break; + + case builtin_unsigned_long: + case builtin_unsigned: /* FIXME: Size depends upon architecture. */ + case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */ + if (strcmp (name, "unsigned long") == 0 + || strcmp (name, "long unsigned int") == 0) + { + indx = builtin_unsigned_long; + found = true; + } + else if (strcmp (name, "unsigned") == 0) + { + indx = builtin_unsigned; + found = true; + } + else if (strcmp (name, "unsigned int") == 0) + { + indx = builtin_unsigned_int; + found = true; + } + break; + + case builtin_signed_long_long: + if (strcmp (name, "signed long long") == 0 + || strcmp (name, "long long int") == 0) + found = true; + break; + + case builtin_unsigned_long_long: + if (strcmp (name, "unsigned long long") == 0 + || strcmp (name, "long long unsigned int") == 0) + found = true; + break; + + case builtin_float: + if (strcmp (name, "float") == 0) + found = true; + break; + + case builtin_double: + if (strcmp (name, "double") == 0) + found = true; + break; + + case builtin_long_double: + if (strcmp (name, "long double") == 0) + found = true; + break; + + case builtin_long_long_double: + if (strcmp (name, "long long double") == 0) + found = true; + break; + } + + if (found) + type.indx = indx; + } + + h = ieee_name_type_hash_lookup (&info->typedefs, name, true, false); + if (h == NULL) + return false; + + /* See if we have already defined this type with this name. */ + localp = type.localp; + for (nt = h->types; nt != NULL; nt = nt->next) + { + if (nt->id == indx) + { + /* If this is a global definition, then we don't need to + do anything here. */ + if (! nt->type.localp) + { + ieee_pop_unused_type (info); + return true; + } + } + else + { + /* This is a duplicate definition, so make this one local. */ + localp = true; + } + } + + /* We need to add a new typedef for this type. */ + + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + nt->id = indx; + nt->type = type; + nt->type.name = name; + nt->type.localp = localp; + nt->kind = DEBUG_KIND_ILLEGAL; + + nt->next = h->types; + h->types = nt; + + if (found) + { + /* This is one of the builtin typedefs, so we don't need to + actually define it. */ + ieee_pop_unused_type (info); + return true; + } + + indx = ieee_pop_type (info); + + if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size, + type.unsignedp, localp, + (struct ieee_buflist *) NULL) + || ! ieee_write_number (info, 'T') + || ! ieee_write_number (info, indx)) + return false; + + /* Remove the type we just added to the type stack. This should not + be ieee_pop_unused_type, since the type is used, we just don't + need it now. */ + (void) ieee_pop_type (info); + + return true; +} + +/* Output a tag for a type. We don't have to do anything here. */ + +static boolean +ieee_tag (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* This should not be ieee_pop_unused_type, since we want the type + to be defined. */ + (void) ieee_pop_type (info); + return true; +} + +/* Output an integer constant. */ + +static boolean +ieee_int_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + /* FIXME. */ + return true; +} + +/* Output a floating point constant. */ + +static boolean +ieee_float_constant (p, name, val) + PTR p; + const char *name; + double val; +{ + /* FIXME. */ + return true; +} + +/* Output a typed constant. */ + +static boolean +ieee_typed_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* FIXME. */ + ieee_pop_unused_type (info); + return true; +} + +/* Output a variable. */ + +static boolean +ieee_variable (p, name, kind, val) + PTR p; + const char *name; + enum debug_var_kind kind; + bfd_vma val; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int name_indx; + unsigned int size; + boolean referencep; + unsigned int type_indx; + boolean asn; + int refflag; + + size = info->type_stack->type.size; + referencep = info->type_stack->type.referencep; + type_indx = ieee_pop_type (info); + + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return false; + + name_indx = info->name_indx; + ++info->name_indx; + + /* Write out an NN and an ATN record for this variable. */ + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_id (info, name) + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_number (info, type_indx)) + return false; + switch (kind) + { + default: + abort (); + return false; + case DEBUG_GLOBAL: + if (! ieee_write_number (info, 8) + || ! ieee_add_range (info, false, val, val + size)) + return false; + refflag = 0; + asn = true; + break; + case DEBUG_STATIC: + if (! ieee_write_number (info, 3) + || ! ieee_add_range (info, false, val, val + size)) + return false; + refflag = 1; + asn = true; + break; + case DEBUG_LOCAL_STATIC: + if (! ieee_write_number (info, 3) + || ! ieee_add_range (info, false, val, val + size)) + return false; + refflag = 2; + asn = true; + break; + case DEBUG_LOCAL: + if (! ieee_write_number (info, 1) + || ! ieee_write_number (info, val)) + return false; + refflag = 2; + asn = false; + break; + case DEBUG_REGISTER: + if (! ieee_write_number (info, 2) + || ! ieee_write_number (info, + ieee_genreg_to_regno (info->abfd, val))) + return false; + refflag = 2; + asn = false; + break; + } + + if (asn) + { + if (! ieee_write_asn (info, name_indx, val)) + return false; + } + + /* If this is really a reference type, then we just output it with + pointer type, and must now output a C++ record indicating that it + is really reference type. */ + if (referencep) + { + unsigned int nindx; + + nindx = info->name_indx; + ++info->name_indx; + + /* If this is a global variable, we want to output the misc + record in the C++ misc record block. Otherwise, we want to + output it just after the variable definition, which is where + the current buffer is. */ + if (refflag != 2) + { + if (! ieee_change_buffer (info, &info->cxx)) + return false; + } + + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 3) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, refflag) + || ! ieee_write_atn65 (info, nindx, name)) + return false; + } + + return true; +} + +/* Start outputting information for a function. */ + +static boolean +ieee_start_function (p, name, global) + PTR p; + const char *name; + boolean global; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + boolean referencep; + unsigned int retindx, typeindx; + + referencep = info->type_stack->type.referencep; + retindx = ieee_pop_type (info); + + /* Besides recording a BB4 or BB6 block, we record the type of the + function in the BB1 typedef block. We can't write out the full + type until we have seen all the parameters, so we accumulate it + in info->fntype and info->fnargs. */ + if (! ieee_buffer_emptyp (&info->fntype)) + { + /* FIXME: This might happen someday if we support nested + functions. */ + abort (); + } + + info->fnname = name; + + /* An attribute of 0x40 means that the push mask is unknown. */ + if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, false, true, + &info->fntype) + || ! ieee_write_number (info, 'x') + || ! ieee_write_number (info, 0x40) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, retindx)) + return false; + + typeindx = ieee_pop_type (info); + + if (! ieee_init_buffer (info, &info->fnargs)) + return false; + info->fnargcount = 0; + + /* If the function return value is actually a reference type, we + must add a record indicating that. */ + if (referencep) + { + unsigned int nindx; + + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->cxx) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 3) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, global ? 0 : 1) + || ! ieee_write_atn65 (info, nindx, name)) + return false; + } + + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return false; + + /* The address is written out as the first block. */ + + ++info->block_depth; + + return (ieee_write_byte (info, (int) ieee_bb_record_enum) + && ieee_write_byte (info, global ? 4 : 6) + && ieee_write_number (info, 0) + && ieee_write_id (info, name) + && ieee_write_number (info, 0) + && ieee_write_number (info, typeindx)); +} + +/* Add a function parameter. This will normally be called before the + first block, so we postpone them until we see the block. */ + +static boolean +ieee_function_parameter (p, name, kind, val) + PTR p; + const char *name; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_pending_parm *m, **pm; + + assert (info->block_depth == 1); + + m = (struct ieee_pending_parm *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->next = NULL; + m->name = name; + m->referencep = info->type_stack->type.referencep; + m->type = ieee_pop_type (info); + m->kind = kind; + m->val = val; + + for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + + /* Add the type to the fnargs list. */ + if (! ieee_change_buffer (info, &info->fnargs) + || ! ieee_write_number (info, m->type)) + return false; + ++info->fnargcount; + + return true; +} + +/* Output pending function parameters. */ + +static boolean +ieee_output_pending_parms (info) + struct ieee_handle *info; +{ + struct ieee_pending_parm *m; + unsigned int refcount; + + refcount = 0; + for (m = info->pending_parms; m != NULL; m = m->next) + { + enum debug_var_kind vkind; + + switch (m->kind) + { + default: + abort (); + return false; + case DEBUG_PARM_STACK: + case DEBUG_PARM_REFERENCE: + vkind = DEBUG_LOCAL; + break; + case DEBUG_PARM_REG: + case DEBUG_PARM_REF_REG: + vkind = DEBUG_REGISTER; + break; + } + + if (! ieee_push_type (info, m->type, 0, false, false)) + return false; + info->type_stack->type.referencep = m->referencep; + if (m->referencep) + ++refcount; + if (! ieee_variable ((PTR) info, m->name, vkind, m->val)) + return false; + } + + /* If there are any reference parameters, we need to output a + miscellaneous record indicating them. */ + if (refcount > 0) + { + unsigned int nindx, varindx; + + /* FIXME: The MRI compiler outputs the demangled function name + here, but we are outputting the mangled name. */ + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, refcount + 3) + || ! ieee_write_asn (info, nindx, 'B') + || ! ieee_write_atn65 (info, nindx, info->fnname) + || ! ieee_write_asn (info, nindx, 0)) + return false; + for (m = info->pending_parms, varindx = 1; + m != NULL; + m = m->next, varindx++) + { + if (m->referencep) + { + if (! ieee_write_asn (info, nindx, varindx)) + return false; + } + } + } + + m = info->pending_parms; + while (m != NULL) + { + struct ieee_pending_parm *next; + + next = m->next; + free (m); + m = next; + } + + info->pending_parms = NULL; + + return true; +} + +/* Start a block. If this is the first block, we output the address + to finish the BB4 or BB6, and then output the function parameters. */ + +static boolean +ieee_start_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + if (! ieee_change_buffer (info, &info->vars)) + return false; + + if (info->block_depth == 1) + { + if (! ieee_write_number (info, addr) + || ! ieee_output_pending_parms (info)) + return false; + } + else + { + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 6) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, addr)) + return false; + } + + if (! ieee_start_range (info, addr)) + return false; + + ++info->block_depth; + + return true; +} + +/* End a block. */ + +static boolean +ieee_end_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* The address we are given is the end of the block, but IEEE seems + to want to the address of the last byte in the block, so we + subtract one. */ + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, addr - 1)) + return false; + + if (! ieee_end_range (info, addr)) + return false; + + --info->block_depth; + + if (addr > info->highaddr) + info->highaddr = addr; + + return true; +} + +/* End a function. */ + +static boolean +ieee_end_function (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->block_depth == 1); + + --info->block_depth; + + /* Now we can finish up fntype, and add it to the typdef section. + At this point, fntype is the 'x' type up to the argument count, + and fnargs is the argument types. We must add the argument + count, and we must add the level. FIXME: We don't record varargs + functions correctly. In fact, stabs debugging does not give us + enough information to do so. */ + if (! ieee_change_buffer (info, &info->fntype) + || ! ieee_write_number (info, info->fnargcount) + || ! ieee_change_buffer (info, &info->fnargs) + || ! ieee_write_number (info, 0)) + return false; + + /* Make sure the typdef block has been started. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return false; + } + + if (! ieee_append_buffer (info, &info->types, &info->fntype) + || ! ieee_append_buffer (info, &info->types, &info->fnargs)) + return false; + + info->fnname = NULL; + if (! ieee_init_buffer (info, &info->fntype) + || ! ieee_init_buffer (info, &info->fnargs)) + return false; + info->fnargcount = 0; + + return true; +} + +/* Record line number information. */ + +static boolean +ieee_lineno (p, filename, lineno, addr) + PTR p; + const char *filename; + unsigned long lineno; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->filename != NULL); + + /* The HP simulator seems to get confused when more than one line is + listed for the same address, at least if they are in different + files. We handle this by always listing the last line for a + given address, since that seems to be the one that gdb uses. */ + if (info->pending_lineno_filename != NULL + && addr != info->pending_lineno_addr) + { + /* Make sure we have a line number block. */ + if (! ieee_buffer_emptyp (&info->linenos)) + { + if (! ieee_change_buffer (info, &info->linenos)) + return false; + } + else + { + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->linenos) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 5) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->filename) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return false; + info->lineno_filename = info->filename; + } + + if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0) + { + if (strcmp (info->filename, info->lineno_filename) != 0) + { + /* We were not in the main file. Close the block for the + included file. */ + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return false; + if (strcmp (info->filename, info->pending_lineno_filename) == 0) + { + /* We need a new NN record, and we aren't about to + output one. */ + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return false; + } + } + if (strcmp (info->filename, info->pending_lineno_filename) != 0) + { + /* We are not changing to the main file. Open a block for + the new included file. */ + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 5) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->pending_lineno_filename) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return false; + } + info->lineno_filename = info->pending_lineno_filename; + } + + if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 7) + || ! ieee_write_number (info, info->pending_lineno) + || ! ieee_write_number (info, 0) + || ! ieee_write_asn (info, info->lineno_name_indx, + info->pending_lineno_addr)) + return false; + } + + info->pending_lineno_filename = filename; + info->pending_lineno = lineno; + info->pending_lineno_addr = addr; + + return true; +} diff --git a/pstack/ieee.h b/pstack/ieee.h new file mode 100644 index 00000000000..5ade39d33e3 --- /dev/null +++ b/pstack/ieee.h @@ -0,0 +1,139 @@ +/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file + Contributed by Cygnus Support. */ + +#define N_W_VARIABLES 8 +#define Module_Beginning 0xe0 + +typedef struct ieee_module { + char *processor; + char *module_name; +} ieee_module_begin_type; + +#define Address_Descriptor 0xec +typedef struct ieee_address { +bfd_vma number_of_bits_mau; + bfd_vma number_of_maus_in_address; + + unsigned char byte_order; +#define IEEE_LITTLE 0xcc +#define IEEE_BIG 0xcd +} ieee_address_descriptor_type; + +typedef union ieee_w_variable { + file_ptr offset[N_W_VARIABLES]; + struct { + file_ptr extension_record; + file_ptr environmental_record; + file_ptr section_part; + file_ptr external_part; + file_ptr debug_information_part; + file_ptr data_part; + file_ptr trailer_part; + file_ptr me_record; + } r; +} ieee_w_variable_type; + + + + + +typedef enum ieee_record +{ + ieee_number_start_enum = 0x00, + ieee_number_end_enum=0x7f, + ieee_number_repeat_start_enum = 0x80, + ieee_number_repeat_end_enum = 0x88, + ieee_number_repeat_4_enum = 0x84, + ieee_number_repeat_3_enum = 0x83, + ieee_number_repeat_2_enum = 0x82, + ieee_number_repeat_1_enum = 0x81, + ieee_module_beginning_enum = 0xe0, + ieee_module_end_enum = 0xe1, + ieee_extension_length_1_enum = 0xde, + ieee_extension_length_2_enum = 0xdf, + ieee_section_type_enum = 0xe6, + ieee_section_alignment_enum = 0xe7, + ieee_external_symbol_enum = 0xe8, + ieee_comma = 0x90, + ieee_external_reference_enum = 0xe9, + ieee_set_current_section_enum = 0xe5, + ieee_address_descriptor_enum = 0xec, + ieee_load_constant_bytes_enum = 0xed, + ieee_load_with_relocation_enum = 0xe4, + + ieee_variable_A_enum = 0xc1, + ieee_variable_B_enum = 0xc2, + ieee_variable_C_enum = 0xc3, + ieee_variable_D_enum = 0xc4, + ieee_variable_E_enum = 0xc5, + ieee_variable_F_enum = 0xc6, + ieee_variable_G_enum = 0xc7, + ieee_variable_H_enum = 0xc8, + ieee_variable_I_enum = 0xc9, + ieee_variable_J_enum = 0xca, + ieee_variable_K_enum = 0xcb, + ieee_variable_L_enum = 0xcc, + ieee_variable_M_enum = 0xcd, + ieee_variable_N_enum = 0xce, + ieee_variable_O_enum = 0xcf, + ieee_variable_P_enum = 0xd0, + ieee_variable_Q_enum = 0xd1, + ieee_variable_R_enum = 0xd2, + ieee_variable_S_enum = 0xd3, + ieee_variable_T_enum = 0xd4, + ieee_variable_U_enum = 0xd5, + ieee_variable_V_enum = 0xd6, + ieee_variable_W_enum = 0xd7, + ieee_variable_X_enum = 0xd8, + ieee_variable_Y_enum = 0xd9, + ieee_variable_Z_enum = 0xda, + ieee_function_plus_enum = 0xa5, + ieee_function_minus_enum = 0xa6, + ieee_function_signed_open_b_enum = 0xba, + ieee_function_signed_close_b_enum = 0xbb, + + ieee_function_unsigned_open_b_enum = 0xbc, + ieee_function_unsigned_close_b_enum = 0xbd, + + ieee_function_either_open_b_enum = 0xbe, + ieee_function_either_close_b_enum = 0xbf, + ieee_record_seperator_enum = 0xdb, + + ieee_e2_first_byte_enum = 0xe2, + ieee_section_size_enum = 0xe2d3, + ieee_physical_region_size_enum = 0xe2c1, + ieee_region_base_address_enum = 0xe2c2, + ieee_mau_size_enum = 0xe2c6, + ieee_m_value_enum = 0xe2cd, + ieee_section_base_address_enum = 0xe2cc, + ieee_asn_record_enum = 0xe2ce, + ieee_section_offset_enum = 0xe2d2, + ieee_value_starting_address_enum = 0xe2c7, + ieee_assign_value_to_variable_enum = 0xe2d7, + ieee_set_current_pc_enum = 0xe2d0, + ieee_value_record_enum = 0xe2c9, + ieee_nn_record = 0xf0, + ieee_at_record_enum = 0xf1, + ieee_ty_record_enum = 0xf2, + ieee_attribute_record_enum = 0xf1c9, + ieee_atn_record_enum = 0xf1ce, + ieee_external_reference_info_record_enum = 0xf1d8, + ieee_weak_external_reference_enum= 0xf4, + ieee_repeat_data_enum = 0xf7, + ieee_bb_record_enum = 0xf8, + ieee_be_record_enum = 0xf9 +} ieee_record_enum_type; + + +typedef struct ieee_section { + unsigned int section_index; + unsigned int section_type; + char *section_name; + unsigned int parent_section_index; + unsigned int sibling_section_index; + unsigned int context_index; +} ieee_section_type; +#define IEEE_REFERENCE_BASE 11 +#define IEEE_PUBLIC_BASE 32 +#define IEEE_SECTION_NUMBER_BASE 1 + diff --git a/pstack/libiberty.h b/pstack/libiberty.h new file mode 100644 index 00000000000..ca0043d31c6 --- /dev/null +++ b/pstack/libiberty.h @@ -0,0 +1,180 @@ +/* Function declarations for libiberty. + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. */ + +#ifndef LIBIBERTY_H +#define LIBIBERTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" + +/* Build an argument vector from a string. Allocates memory using + malloc. Use freeargv to free the vector. */ + +extern char **buildargv PARAMS ((char *)); + +/* Free a vector returned by buildargv. */ + +extern void freeargv PARAMS ((char **)); + +/* Duplicate an argument vector. Allocates memory using malloc. Use + freeargv to free the vector. */ + +extern char **dupargv PARAMS ((char **)); + + +/* Return the last component of a path name. Note that we can't use a + prototype here because the parameter is declared inconsistently + across different systems, sometimes as "char *" and sometimes as + "const char *" */ + +#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) +extern char *basename PARAMS ((const char *)); +#else +extern char *basename (); +#endif + +/* Concatenate an arbitrary number of strings, up to (char *) NULL. + Allocates memory using xmalloc. */ + +extern char *concat PARAMS ((const char *, ...)); + +/* Check whether two file descriptors refer to the same file. */ + +extern int fdmatch PARAMS ((int fd1, int fd2)); + +/* Get the amount of time the process has run, in microseconds. */ + +extern long get_run_time PARAMS ((void)); + +/* Choose a temporary directory to use for scratch files. */ + +extern char *choose_temp_base PARAMS ((void)); + +/* Allocate memory filled with spaces. Allocates using malloc. */ + +extern const char *spaces PARAMS ((int count)); + +/* Return the maximum error number for which strerror will return a + string. */ + +extern int errno_max PARAMS ((void)); + +/* Return the name of an errno value (e.g., strerrno (EINVAL) returns + "EINVAL"). */ + +extern const char *strerrno PARAMS ((int)); + +/* Given the name of an errno value, return the value. */ + +extern int strtoerrno PARAMS ((const char *)); + +/* ANSI's strerror(), but more robust. */ + +extern char *xstrerror PARAMS ((int)); + +/* Return the maximum signal number for which strsignal will return a + string. */ + +extern int signo_max PARAMS ((void)); + +/* Return a signal message string for a signal number + (e.g., strsignal (SIGHUP) returns something like "Hangup"). */ +/* This is commented out as it can conflict with one in system headers. + We still document its existence though. */ + +/*extern const char *strsignal PARAMS ((int));*/ + +/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns + "SIGHUP"). */ + +extern const char *strsigno PARAMS ((int)); + +/* Given the name of a signal, return its number. */ + +extern int strtosigno PARAMS ((const char *)); + +/* Register a function to be run by xexit. Returns 0 on success. */ + +extern int xatexit PARAMS ((void (*fn) (void))); + +/* Exit, calling all the functions registered with xatexit. */ + +#ifndef __GNUC__ +extern void xexit PARAMS ((int status)); +#else +void xexit PARAMS ((int status)) __attribute__ ((noreturn)); +#endif + +/* Set the program name used by xmalloc. */ + +extern void xmalloc_set_program_name PARAMS ((const char *)); + +/* Allocate memory without fail. If malloc fails, this will print a + message to stderr (using the name set by xmalloc_set_program_name, + if any) and then call xexit. */ + +#ifdef ANSI_PROTOTYPES +/* Get a definition for size_t. */ +#include <stddef.h> +#endif +extern PTR xmalloc PARAMS ((size_t)); + +/* Reallocate memory without fail. This works like xmalloc. + + FIXME: We do not declare the parameter types for the same reason as + xmalloc. */ + +extern PTR xrealloc PARAMS ((PTR, size_t)); + +/* Allocate memory without fail and set it to zero. This works like + xmalloc. */ + +extern PTR xcalloc PARAMS ((size_t, size_t)); + +/* Copy a string into a memory buffer without fail. */ + +extern char *xstrdup PARAMS ((const char *)); + +/* hex character manipulation routines */ + +#define _hex_array_size 256 +#define _hex_bad 99 +extern char _hex_value[_hex_array_size]; +extern void hex_init PARAMS ((void)); +#define hex_p(c) (hex_value (c) != _hex_bad) +/* If you change this, note well: Some code relies on side effects in + the argument being performed exactly once. */ +#define hex_value(c) (_hex_value[(unsigned char) (c)]) + +/* Definitions used by the pexecute routine. */ + +#define PEXECUTE_FIRST 1 +#define PEXECUTE_LAST 2 +#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST) +#define PEXECUTE_SEARCH 4 +#define PEXECUTE_VERBOSE 8 + +/* Execute a program. */ + +extern int pexecute PARAMS ((const char *, char * const *, const char *, + const char *, char **, char **, int)); + +/* Wait for pexecute to finish. */ + +extern int pwait PARAMS ((int, int *, int)); + +#ifdef __cplusplus +} +#endif + + +#endif /* ! defined (LIBIBERTY_H) */ diff --git a/pstack/linuxthreads.c b/pstack/linuxthreads.c new file mode 100644 index 00000000000..8624bd21782 --- /dev/null +++ b/pstack/linuxthreads.c @@ -0,0 +1,90 @@ +/* $Header$ */ + +/* + * LinuxThreads specific stuff. + */ + +#include <sys/types.h> + +#include <assert.h> +#include <limits.h> /* PTHREAD_THREADS_MAX */ +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <sched.h> + +#include "linuxthreads.h" + +#define AT_INT(intval) *((int32_t*)(intval)) + +/* + * Internal LinuxThreads variables. + * Official interface exposed to GDB. + */ +#if 1 +extern volatile int __pthread_threads_debug; +extern volatile char __pthread_handles; +extern char __pthread_initial_thread; +/*extern volatile Elf32_Sym* __pthread_manager_thread;*/ +extern const int __pthread_sizeof_handle; +extern const int __pthread_offsetof_descr; +extern const int __pthread_offsetof_pid; +extern volatile int __pthread_handles_num; +#endif /* 0 */ + +/* + * Notify others. + */ +int +linuxthreads_notify_others( const int signotify) +{ + const pid_t mypid = getpid(); + //const pthread_t mytid = pthread_self(); + int i; + int threadcount = 0; + int threads[PTHREAD_THREADS_MAX]; + int pid; + + TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num)); + if (__pthread_handles_num==2) { + /* no threads beside the initial thread */ + return 0; + } + /*assert(maxthreads>=3); + assert(maxthreads>=__pthread_handles_num+2);*/ + + // take the initial thread with us + pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid); + if (pid!=mypid && pid!=0) + threads[threadcount++] = pid; + // don't know why, but always handles[0]==handles[1] + for (i=1; i<__pthread_handles_num; ++i) { + const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr); + assert(descr!=0); + pid = AT_INT(descr+__pthread_offsetof_pid); + if (pid!=mypid && pid!=0) + threads[threadcount++] = pid; + } + /* TRACE_FPRINTF((stderr, "Stopping threads...")); */ + //for (i=0; i<threadcount; ++i) { + // /* TRACE_FPRINTF((stderr, "%d ", threads[i])); */ + // fflush(stdout); + // kill(threads[i], SIGSTOP); /* Tell thread to stop */ + //} + /* TRACE_FPRINTF((stderr, " done!\n")); */ + for (i=0; i<threadcount; ++i) { + TRACE_FPRINTF((stderr, "--- NOTIFYING %d\n", threads[i])); + kill(threads[i], signotify); /* Tell to print stack trace */ + /* TRACE_FPRINTF((stderr, "--- WAITING FOR %d\n", threads[i])); */ + /*pause(); Wait for confirmation. */ + } + for (i=0; i<threadcount; ++i) + sched_yield(); + for (i=0; i<threadcount; ++i) { + TRACE_FPRINTF((stderr, "--- KILLING %d\n", threads[i])); + kill(threads[i], SIGKILL); /* Tell thread die :) */ + } + return __pthread_handles_num; +} + diff --git a/pstack/linuxthreads.h b/pstack/linuxthreads.h new file mode 100644 index 00000000000..f5eb0f652d8 --- /dev/null +++ b/pstack/linuxthreads.h @@ -0,0 +1,28 @@ +/* $Header$ */ + +/* + * LinuxThreads specific stuff. + */ + +#ifndef pstack_linuxthreads_h_ +#define pstack_linuxthreads_h_ + +#include <pthread.h> +#include "pstacktrace.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Tell other threads to dump stacks... + */ +int +linuxthreads_notify_others( const int signotify); + +#ifdef __cplusplus +} +#endif + +#endif /* pstack_linuxthreads_h_ */ + diff --git a/pstack/pstack.c b/pstack/pstack.c new file mode 100644 index 00000000000..1132dcd83f7 --- /dev/null +++ b/pstack/pstack.c @@ -0,0 +1,2746 @@ +/* + pstack.c -- asynchronous stack trace of a running process + Copyright (c) 1999 Ross Thompson + Author: Ross Thompson <ross@whatsis.com> + Critical bug fix: Tim Waugh +*/ + +/* + This file 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. +*/ + +/* RESTRICTIONS: + + pstack currently works only on Linux, only on an x86 machine running + 32 bit ELF binaries (64 bit not supported). Also, for symbolic + information, you need to use a GNU compiler to generate your + program, and you can't strip symbols from the binaries. For thread + information to be dumped, you have to use the debug-aware version + of libpthread.so. (To check, run 'nm' on your libpthread.so, and + make sure that the symbol "__pthread_threads_debug" is defined.) + + The details of pulling stuff out of ELF files and running through + program images is very platform specific, and I don't want to + try to support modes or machine types I can't test in or on. + If someone wants to generalize this to other architectures, I would + be happy to help and coordinate the activity. Please send me whatever + changes you make to support these machines, so that I can own the + central font of all truth (at least as regards this program). + + Thanks +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include <asm/ptrace.h> + +#include <assert.h> +#include <fcntl.h> +#include <link.h> +#include <malloc.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include <limits.h> /* PTHREAD_THREADS_MAX */ + + +#include <bfd.h> + +#include "libiberty.h" + +#include "pstack.h" /* just one function */ +#include "budbg.h" /* binutils stuff related to debugging symbols. */ +#include "bucomm.h" /* some common stuff */ +#include "debug.h" /* and more binutils stuff... */ +#include "budbg.h" +#include "linuxthreads.h" /* LinuxThreads specific stuff... */ + + +/* + * fprintf for file descriptors :) NOTE: we have to use fixed-size buffer :)( + * due to malloc's unavalaibility. + */ +int +fdprintf( int fd, + const char* fmt,...) +{ + char xbuf[2048];// FIXME: enough? + va_list ap; + int r; + if (fd<0) + return -1; + va_start(ap, fmt); + r = vsnprintf(xbuf, sizeof(xbuf), fmt, ap); + va_end(ap); + return write(fd, xbuf, r); +} + +int +fdputc( char c, + int fd) +{ + if (fd<0) + return -1; + return write(fd, &c, sizeof(c)); +} + +int +fdputs( const char* s, + int fd) +{ + if (fd<0) + return -1; + return write(fd, s, strlen(s)); +} + +/* + * Use this function to open log file. + * Flags: truncate on opening. + */ +static const char* path_format = "stack-trace-on-segv-%d.txt"; +static int +open_log_file( const pthread_t tid, + const pid_t pid) +{ + char fname[PATH_MAX]; + int r; + snprintf(fname, sizeof(fname), path_format, tid, pid); + r = open(fname, O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR|S_IWUSR); + if (r<0) + perror("open"); + return r; +} +/* + * Add additional debugging information for functions. + */ + +/* + * Lineno + */ +typedef struct { + int lineno; + bfd_vma addr; +} debug_lineno_t; + +/* + * Block - a {} pair. + */ +typedef struct debug_block_st { + bfd_vma begin_addr; /* where did it start */ + bfd_vma end_addr; /* where did it end */ + struct debug_block_st* parent; + struct debug_block_st* childs; + int childs_count; +} debug_block_t; + +/* + * Function parameter. + */ +typedef struct { + bfd_vma offset; /* Offset in the stack */ + const char* name; /* And name. */ +} debug_parameter_t; + +/* + * Extra information about functions. + */ +typedef struct { + asymbol* symbol; /* mangled function name, addr */ + debug_lineno_t* lines; + int lines_count; + int max_lines_count; + const char* name; + const char* filename;/* a file name it occured in... */ + debug_block_t* block; /* each function has a block, or not, you know */ + debug_parameter_t* argv; /* argument types. */ + int argc; + int max_argc; +} debug_function_t; + +/* This is the structure we use as a handle for these routines. */ +struct pr_handle +{ + /* File to print information to. */ + FILE *f; + /* Current indentation level. */ + unsigned int indent; + /* Type stack. */ + struct pr_stack *stack; + /* Parameter number we are about to output. */ + int parameter; + debug_block_t* block; /* current block */ + debug_function_t* function; /* current function */ + debug_function_t* functions; /* all functions */ + int functions_size; /* current size */ + int functions_maxsize; /* maximum size */ +}; + +/* The type stack. */ + +struct pr_stack +{ + /* Next element on the stack. */ + struct pr_stack *next; + /* This element. */ + char *type; + /* Current visibility of fields if this is a class. */ + enum debug_visibility visibility; + /* Name of the current method we are handling. */ + const char *method; +}; + +static void indent PARAMS ((struct pr_handle *)); +static boolean push_type PARAMS ((struct pr_handle *, const char *)); +static boolean prepend_type PARAMS ((struct pr_handle *, const char *)); +static boolean append_type PARAMS ((struct pr_handle *, const char *)); +static boolean substitute_type PARAMS ((struct pr_handle *, const char *)); +static boolean indent_type PARAMS ((struct pr_handle *)); +static char *pop_type PARAMS ((struct pr_handle *)); +static void print_vma PARAMS ((bfd_vma, char *, boolean, boolean)); +static boolean pr_fix_visibility + PARAMS ((struct pr_handle *, enum debug_visibility)); + +static boolean pr_start_compilation_unit PARAMS ((PTR, const char *)); +static boolean pr_start_source PARAMS ((PTR, const char *)); +static boolean pr_empty_type PARAMS ((PTR)); +static boolean pr_void_type PARAMS ((PTR)); +static boolean pr_int_type PARAMS ((PTR, unsigned int, boolean)); +static boolean pr_float_type PARAMS ((PTR, unsigned int)); +static boolean pr_complex_type PARAMS ((PTR, unsigned int)); +static boolean pr_bool_type PARAMS ((PTR, unsigned int)); +static boolean pr_enum_type + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); +static boolean pr_pointer_type PARAMS ((PTR)); +static boolean pr_function_type PARAMS ((PTR, int, boolean)); +static boolean pr_reference_type PARAMS ((PTR)); +static boolean pr_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); +static boolean pr_array_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean)); +static boolean pr_set_type PARAMS ((PTR, boolean)); +static boolean pr_offset_type PARAMS ((PTR)); +static boolean pr_method_type PARAMS ((PTR, boolean, int, boolean)); +static boolean pr_const_type PARAMS ((PTR)); +static boolean pr_volatile_type PARAMS ((PTR)); +static boolean pr_start_struct_type + PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int)); +static boolean pr_struct_field + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); +static boolean pr_end_struct_type PARAMS ((PTR)); +static boolean pr_start_class_type + PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean, + boolean)); +static boolean pr_class_static_member + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); +static boolean pr_class_baseclass + PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility)); +static boolean pr_class_start_method PARAMS ((PTR, const char *)); +static boolean pr_class_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean, + bfd_vma, boolean)); +static boolean pr_class_static_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean)); +static boolean pr_class_end_method PARAMS ((PTR)); +static boolean pr_end_class_type PARAMS ((PTR)); +static boolean pr_typedef_type PARAMS ((PTR, const char *)); +static boolean pr_tag_type + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); +static boolean pr_typdef PARAMS ((PTR, const char *)); +static boolean pr_tag PARAMS ((PTR, const char *)); +static boolean pr_int_constant PARAMS ((PTR, const char *, bfd_vma)); +static boolean pr_float_constant PARAMS ((PTR, const char *, double)); +static boolean pr_typed_constant PARAMS ((PTR, const char *, bfd_vma)); +static boolean pr_variable + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); +static boolean pr_start_function PARAMS ((PTR, const char *, boolean)); +static boolean pr_function_parameter + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); +static boolean pr_start_block PARAMS ((PTR, bfd_vma)); +static boolean pr_end_block PARAMS ((PTR, bfd_vma)); +static boolean pr_end_function PARAMS ((PTR)); +static boolean pr_lineno PARAMS ((PTR, const char *, unsigned long, bfd_vma)); + +static const struct debug_write_fns pr_fns = +{ + pr_start_compilation_unit, + pr_start_source, + pr_empty_type, + pr_void_type, + pr_int_type, + pr_float_type, + pr_complex_type, + pr_bool_type, + pr_enum_type, + pr_pointer_type, + pr_function_type, + pr_reference_type, + pr_range_type, + pr_array_type, + pr_set_type, + pr_offset_type, + pr_method_type, + pr_const_type, + pr_volatile_type, + pr_start_struct_type, + pr_struct_field, + pr_end_struct_type, + pr_start_class_type, + pr_class_static_member, + pr_class_baseclass, + pr_class_start_method, + pr_class_method_variant, + pr_class_static_method_variant, + pr_class_end_method, + pr_end_class_type, + pr_typedef_type, + pr_tag_type, + pr_typdef, + pr_tag, + pr_int_constant, + pr_float_constant, + pr_typed_constant, + pr_variable, + pr_start_function, + pr_function_parameter, + pr_start_block, + pr_end_block, + pr_end_function, + pr_lineno +}; + + +/* Indent to the current indentation level. */ + +static void +indent (info) + struct pr_handle *info; +{ + unsigned int i; + + for (i = 0; i < info->indent; i++) + TRACE_PUTC ((' ', info->f)); +} + +/* Push a type on the type stack. */ + +static boolean +push_type (info, type) + struct pr_handle *info; + const char *type; +{ + struct pr_stack *n; + + if (type == NULL) + return false; + + n = (struct pr_stack *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = xstrdup (type); + n->visibility = DEBUG_VISIBILITY_IGNORE; + n->method = NULL; + n->next = info->stack; + info->stack = n; + + return true; +} + +/* Prepend a string onto the type on the top of the type stack. */ + +static boolean +prepend_type (info, s) + struct pr_handle *info; + const char *s; +{ + char *n; + + assert (info->stack != NULL); + + n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1); + sprintf (n, "%s%s", s, info->stack->type); + free (info->stack->type); + info->stack->type = n; + + return true; +} + +/* Append a string to the type on the top of the type stack. */ + +static boolean +append_type (info, s) + struct pr_handle *info; + const char *s; +{ + unsigned int len; + + if (s == NULL) + return false; + + assert (info->stack != NULL); + + len = strlen (info->stack->type); + info->stack->type = (char *) xrealloc (info->stack->type, + len + strlen (s) + 1); + strcpy (info->stack->type + len, s); + + return true; +} + +/* We use an underscore to indicate where the name should go in a type + string. This function substitutes a string for the underscore. If + there is no underscore, the name follows the type. */ + +static boolean +substitute_type (info, s) + struct pr_handle *info; + const char *s; +{ + char *u; + + assert (info->stack != NULL); + + u = strchr (info->stack->type, '|'); + if (u != NULL) + { + char *n; + + n = (char *) xmalloc (strlen (info->stack->type) + strlen (s)); + + memcpy (n, info->stack->type, u - info->stack->type); + strcpy (n + (u - info->stack->type), s); + strcat (n, u + 1); + + free (info->stack->type); + info->stack->type = n; + + return true; + } + + if (strchr (s, '|') != NULL + && (strchr (info->stack->type, '{') != NULL + || strchr (info->stack->type, '(') != NULL)) + { + if (! prepend_type (info, "(") + || ! append_type (info, ")")) + return false; + } + + if (*s == '\0') + return true; + + return (append_type (info, " ") + && append_type (info, s)); +} + +/* Indent the type at the top of the stack by appending spaces. */ + +static boolean +indent_type (info) + struct pr_handle *info; +{ + unsigned int i; + + for (i = 0; i < info->indent; i++) + { + if (! append_type (info, " ")) + return false; + } + + return true; +} + +/* Pop a type from the type stack. */ + +static char * +pop_type (info) + struct pr_handle *info; +{ + struct pr_stack *o; + char *ret; + + assert (info->stack != NULL); + + o = info->stack; + info->stack = o->next; + ret = o->type; + free (o); + + return ret; +} + +/* Print a VMA value into a string. */ + +static void +print_vma (vma, buf, unsignedp, hexp) + bfd_vma vma; + char *buf; + boolean unsignedp; + boolean hexp; +{ + if (sizeof (vma) <= sizeof (unsigned long)) + { + if (hexp) + sprintf (buf, "0x%lx", (unsigned long) vma); + else if (unsignedp) + sprintf (buf, "%lu", (unsigned long) vma); + else + sprintf (buf, "%ld", (long) vma); + } + else + { + buf[0] = '0'; + buf[1] = 'x'; + sprintf_vma (buf + 2, vma); + } +} + +/* Start a new compilation unit. */ + +static boolean +pr_start_compilation_unit (p, filename) + PTR p; + const char *filename; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->indent == 0); +/* + TRACE_FPRINTF( (info->f, "%s:\n", filename)); +*/ + return true; +} + +/* Start a source file within a compilation unit. */ + +static boolean +pr_start_source (p, filename) + PTR p; + const char *filename; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->indent == 0); +/* + TRACE_FPRINTF( (info->f, " %s:\n", filename)); +*/ + return true; +} + +/* Push an empty type onto the type stack. */ + +static boolean +pr_empty_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, "<undefined>"); +} + +/* Push a void type onto the type stack. */ + +static boolean +pr_void_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, "void"); +} + +/* Push an integer type onto the type stack. */ + +static boolean +pr_int_type (p, size, unsignedp) + PTR p; + unsigned int size; + boolean unsignedp; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8); + return push_type (info, ab); +} + +/* Push a floating type onto the type stack. */ + +static boolean +pr_float_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + if (size == 4) + return push_type (info, "float"); + else if (size == 8) + return push_type (info, "double"); + + sprintf (ab, "float%d", size * 8); + return push_type (info, ab); +} + +/* Push a complex type onto the type stack. */ + +static boolean +pr_complex_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + + if (! pr_float_type (p, size)) + return false; + + return prepend_type (info, "complex "); +} + +/* Push a boolean type onto the type stack. */ + +static boolean +pr_bool_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + sprintf (ab, "bool%d", size * 8); + + return push_type (info, ab); +} + +/* Push an enum type onto the type stack. */ + +static boolean +pr_enum_type (p, tag, names, values) + PTR p; + const char *tag; + const char **names; + bfd_signed_vma *values; +{ + struct pr_handle *info = (struct pr_handle *) p; + unsigned int i; + bfd_signed_vma val; + + if (! push_type (info, "enum ")) + return false; + if (tag != NULL) + { + if (! append_type (info, tag) + || ! append_type (info, " ")) + return false; + } + if (! append_type (info, "{ ")) + return false; + + if (names == NULL) + { + if (! append_type (info, "/* undefined */")) + return false; + } + else + { + val = 0; + for (i = 0; names[i] != NULL; i++) + { + if (i > 0) + { + if (! append_type (info, ", ")) + return false; + } + + if (! append_type (info, names[i])) + return false; + + if (values[i] != val) + { + char ab[20]; + + print_vma (values[i], ab, false, false); + if (! append_type (info, " = ") + || ! append_type (info, ab)) + return false; + val = values[i]; + } + + ++val; + } + } + + return append_type (info, " }"); +} + +/* Turn the top type on the stack into a pointer. */ + +static boolean +pr_pointer_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + assert (info->stack != NULL); + + s = strchr (info->stack->type, '|'); + if (s != NULL && s[1] == '[') + return substitute_type (info, "(*|)"); + return substitute_type (info, "*|"); +} + +/* Turn the top type on the stack into a function returning that type. */ + +static boolean +pr_function_type (p, argcount, varargs) + PTR p; + int argcount; + boolean varargs; +{ + struct pr_handle *info = (struct pr_handle *) p; + char **arg_types; + unsigned int len; + char *s; + + assert (info->stack != NULL); + + len = 10; + + if (argcount <= 0) + { + arg_types = NULL; + len += 15; + } + else + { + int i; + + arg_types = (char **) xmalloc (argcount * sizeof *arg_types); + for (i = argcount - 1; i >= 0; i--) + { + if (! substitute_type (info, "")) + return false; + arg_types[i] = pop_type (info); + if (arg_types[i] == NULL) + return false; + len += strlen (arg_types[i]) + 2; + } + if (varargs) + len += 5; + } + + /* Now the return type is on the top of the stack. */ + + s = (char *) xmalloc (len); + strcpy (s, "(|) ("); + + if (argcount < 0) + { +#if 0 + /* Turn off unknown arguments. */ + strcat (s, "/* unknown */"); +#endif + } + else + { + int i; + + for (i = 0; i < argcount; i++) + { + if (i > 0) + strcat (s, ", "); + strcat (s, arg_types[i]); + } + if (varargs) + { + if (i > 0) + strcat (s, ", "); + strcat (s, "..."); + } + if (argcount > 0) + free (arg_types); + } + + strcat (s, ")"); + + if (! substitute_type (info, s)) + return false; + + free (s); + + return true; +} + +/* Turn the top type on the stack into a reference to that type. */ + +static boolean +pr_reference_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->stack != NULL); + + return substitute_type (info, "&|"); +} + +/* Make a range type. */ + +static boolean +pr_range_type (p, lower, upper) + PTR p; + bfd_signed_vma lower; + bfd_signed_vma upper; +{ + struct pr_handle *info = (struct pr_handle *) p; + char abl[20], abu[20]; + + assert (info->stack != NULL); + + if (! substitute_type (info, "")) + return false; + + print_vma (lower, abl, false, false); + print_vma (upper, abu, false, false); + + return (prepend_type (info, "range (") + && append_type (info, "):") + && append_type (info, abl) + && append_type (info, ":") + && append_type (info, abu)); +} + +/* Make an array type. */ + +/*ARGSUSED*/ +static boolean +pr_array_type (p, lower, upper, stringp) + PTR p; + bfd_signed_vma lower; + bfd_signed_vma upper; + boolean stringp; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *range_type; + char abl[20], abu[20], ab[50]; + + range_type = pop_type (info); + if (range_type == NULL) + return false; + + if (lower == 0) + { + if (upper == -1) + sprintf (ab, "|[]"); + else + { + print_vma (upper + 1, abu, false, false); + sprintf (ab, "|[%s]", abu); + } + } + else + { + print_vma (lower, abl, false, false); + print_vma (upper, abu, false, false); + sprintf (ab, "|[%s:%s]", abl, abu); + } + + if (! substitute_type (info, ab)) + return false; + + if (strcmp (range_type, "int") != 0) + { + if (! append_type (info, ":") + || ! append_type (info, range_type)) + return false; + } + + if (stringp) + { + if (! append_type (info, " /* string */")) + return false; + } + + return true; +} + +/* Make a set type. */ + +/*ARGSUSED*/ +static boolean +pr_set_type (p, bitstringp) + PTR p; + boolean bitstringp; +{ + struct pr_handle *info = (struct pr_handle *) p; + + if (! substitute_type (info, "")) + return false; + + if (! prepend_type (info, "set { ") + || ! append_type (info, " }")) + return false; + + if (bitstringp) + { + if (! append_type (info, "/* bitstring */")) + return false; + } + + return true; +} + +/* Make an offset type. */ + +static boolean +pr_offset_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, "")) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + + return (substitute_type (info, "") + && prepend_type (info, " ") + && prepend_type (info, t) + && append_type (info, "::|")); +} + +/* Make a method type. */ + +static boolean +pr_method_type (p, domain, argcount, varargs) + PTR p; + boolean domain; + int argcount; + boolean varargs; +{ + struct pr_handle *info = (struct pr_handle *) p; + unsigned int len; + char *domain_type; + char **arg_types; + char *s; + + len = 10; + + if (! domain) + domain_type = NULL; + else + { + if (! substitute_type (info, "")) + return false; + domain_type = pop_type (info); + if (domain_type == NULL) + return false; + if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0 + && strchr (domain_type + sizeof "class " - 1, ' ') == NULL) + domain_type += sizeof "class " - 1; + else if (strncmp (domain_type, "union class ", + sizeof "union class ") == 0 + && (strchr (domain_type + sizeof "union class " - 1, ' ') + == NULL)) + domain_type += sizeof "union class " - 1; + len += strlen (domain_type); + } + + if (argcount <= 0) + { + arg_types = NULL; + len += 15; + } + else + { + int i; + + arg_types = (char **) xmalloc (argcount * sizeof *arg_types); + for (i = argcount - 1; i >= 0; i--) + { + if (! substitute_type (info, "")) + return false; + arg_types[i] = pop_type (info); + if (arg_types[i] == NULL) + return false; + len += strlen (arg_types[i]) + 2; + } + if (varargs) + len += 5; + } + + /* Now the return type is on the top of the stack. */ + + s = (char *) xmalloc (len); + if (! domain) + *s = '\0'; + else + strcpy (s, domain_type); + strcat (s, "::| ("); + + if (argcount < 0) + strcat (s, "/* unknown */"); + else + { + int i; + + for (i = 0; i < argcount; i++) + { + if (i > 0) + strcat (s, ", "); + strcat (s, arg_types[i]); + } + if (varargs) + { + if (i > 0) + strcat (s, ", "); + strcat (s, "..."); + } + if (argcount > 0) + free (arg_types); + } + + strcat (s, ")"); + + if (! substitute_type (info, s)) + return false; + + free (s); + + return true; +} + +/* Make a const qualified type. */ + +static boolean +pr_const_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return substitute_type (info, "const |"); +} + +/* Make a volatile qualified type. */ + +static boolean +pr_volatile_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return substitute_type (info, "volatile |"); +} + +/* Start accumulating a struct type. */ + +static boolean +pr_start_struct_type (p, tag, id, structp, size) + PTR p; + const char *tag; + unsigned int id; + boolean structp; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + + info->indent += 2; + + if (! push_type (info, structp ? "struct " : "union ")) + return false; + if (tag != NULL) + { + if (! append_type (info, tag)) + return false; + } + else + { + char idbuf[20]; + + sprintf (idbuf, "%%anon%u", id); + if (! append_type (info, idbuf)) + return false; + } + + if (! append_type (info, " {")) + return false; + if (size != 0 || tag != NULL) + { + char ab[30]; + + if (! append_type (info, " /*")) + return false; + + if (size != 0) + { + sprintf (ab, " size %u", size); + if (! append_type (info, ab)) + return false; + } + if (tag != NULL) + { + sprintf (ab, " id %u", id); + if (! append_type (info, ab)) + return false; + } + if (! append_type (info, " */")) + return false; + } + if (! append_type (info, "\n")) + return false; + + info->stack->visibility = DEBUG_VISIBILITY_PUBLIC; + + return indent_type (info); +} + +/* Output the visibility of a field in a struct. */ + +static boolean +pr_fix_visibility (info, visibility) + struct pr_handle *info; + enum debug_visibility visibility; +{ + const char *s; + char *t; + unsigned int len; + + assert (info->stack != NULL); + + if (info->stack->visibility == visibility) + return true; + + assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE); + + switch (visibility) + { + case DEBUG_VISIBILITY_PUBLIC: + s = "public"; + break; + case DEBUG_VISIBILITY_PRIVATE: + s = "private"; + break; + case DEBUG_VISIBILITY_PROTECTED: + s = "protected"; + break; + case DEBUG_VISIBILITY_IGNORE: + s = "/* ignore */"; + break; + default: + abort (); + return false; + } + + /* Trim off a trailing space in the struct string, to make the + output look a bit better, then stick on the visibility string. */ + + t = info->stack->type; + len = strlen (t); + assert (t[len - 1] == ' '); + t[len - 1] = '\0'; + + if (! append_type (info, s) + || ! append_type (info, ":\n") + || ! indent_type (info)) + return false; + + info->stack->visibility = visibility; + + return true; +} + +/* Add a field to a struct type. */ + +static boolean +pr_struct_field (p, name, bitpos, bitsize, visibility) + PTR p; + const char *name; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + char *t; + + if (! substitute_type (info, name)) + return false; + + if (! append_type (info, "; /* ")) + return false; + + if (bitsize != 0) + { + print_vma (bitsize, ab, true, false); + if (! append_type (info, "bitsize ") + || ! append_type (info, ab) + || ! append_type (info, ", ")) + return false; + } + + print_vma (bitpos, ab, true, false); + if (! append_type (info, "bitpos ") + || ! append_type (info, ab) + || ! append_type (info, " */\n") + || ! indent_type (info)) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + + if (! pr_fix_visibility (info, visibility)) + return false; + + return append_type (info, t); +} + +/* Finish a struct type. */ + +static boolean +pr_end_struct_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + assert (info->stack != NULL); + assert (info->indent >= 2); + + info->indent -= 2; + + /* Change the trailing indentation to have a close brace. */ + s = info->stack->type + strlen (info->stack->type) - 2; + assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0'); + + *s++ = '}'; + *s = '\0'; + + return true; +} + +/* Start a class type. */ + +static boolean +pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr) + PTR p; + const char *tag; + unsigned int id; + boolean structp; + unsigned int size; + boolean vptr; + boolean ownvptr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *tv = NULL; + + info->indent += 2; + + if (vptr && ! ownvptr) + { + tv = pop_type (info); + if (tv == NULL) + return false; + } + + if (! push_type (info, structp ? "class " : "union class ")) + return false; + if (tag != NULL) + { + if (! append_type (info, tag)) + return false; + } + else + { + char idbuf[20]; + + sprintf (idbuf, "%%anon%u", id); + if (! append_type (info, idbuf)) + return false; + } + + if (! append_type (info, " {")) + return false; + if (size != 0 || vptr || ownvptr || tag != NULL) + { + if (! append_type (info, " /*")) + return false; + + if (size != 0) + { + char ab[20]; + + sprintf (ab, "%u", size); + if (! append_type (info, " size ") + || ! append_type (info, ab)) + return false; + } + + if (vptr) + { + if (! append_type (info, " vtable ")) + return false; + if (ownvptr) + { + if (! append_type (info, "self ")) + return false; + } + else + { + if (! append_type (info, tv) + || ! append_type (info, " ")) + return false; + } + } + + if (tag != NULL) + { + char ab[30]; + + sprintf (ab, " id %u", id); + if (! append_type (info, ab)) + return false; + } + + if (! append_type (info, " */")) + return false; + } + + info->stack->visibility = DEBUG_VISIBILITY_PRIVATE; + + return (append_type (info, "\n") + && indent_type (info)); +} + +/* Add a static member to a class. */ + +static boolean +pr_class_static_member (p, name, physname, visibility) + PTR p; + const char *name; + const char *physname; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, name)) + return false; + + if (! prepend_type (info, "static ") + || ! append_type (info, "; /* ") + || ! append_type (info, physname) + || ! append_type (info, " */\n") + || ! indent_type (info)) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + + if (! pr_fix_visibility (info, visibility)) + return false; + + return append_type (info, t); +} + +/* Add a base class to a class. */ + +static boolean +pr_class_baseclass (p, bitpos, virtual, visibility) + PTR p; + bfd_vma bitpos; + boolean virtual; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + const char *prefix; + char ab[20]; + char *s, *l, *n; + + assert (info->stack != NULL && info->stack->next != NULL); + + if (! substitute_type (info, "")) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + + if (strncmp (t, "class ", sizeof "class " - 1) == 0) + t += sizeof "class " - 1; + + /* Push it back on to take advantage of the prepend_type and + append_type routines. */ + if (! push_type (info, t)) + return false; + + if (virtual) + { + if (! prepend_type (info, "virtual ")) + return false; + } + + switch (visibility) + { + case DEBUG_VISIBILITY_PUBLIC: + prefix = "public "; + break; + case DEBUG_VISIBILITY_PROTECTED: + prefix = "protected "; + break; + case DEBUG_VISIBILITY_PRIVATE: + prefix = "private "; + break; + default: + prefix = "/* unknown visibility */ "; + break; + } + + if (! prepend_type (info, prefix)) + return false; + + if (bitpos != 0) + { + print_vma (bitpos, ab, true, false); + if (! append_type (info, " /* bitpos ") + || ! append_type (info, ab) + || ! append_type (info, " */")) + return false; + } + + /* Now the top of the stack is something like "public A / * bitpos + 10 * /". The next element on the stack is something like "class + xx { / * size 8 * /\n...". We want to substitute the top of the + stack in before the {. */ + s = strchr (info->stack->next->type, '{'); + assert (s != NULL); + --s; + + /* If there is already a ':', then we already have a baseclass, and + we must append this one after a comma. */ + for (l = info->stack->next->type; l != s; l++) + if (*l == ':') + break; + if (! prepend_type (info, l == s ? " : " : ", ")) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + + n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1); + memcpy (n, info->stack->type, s - info->stack->type); + strcpy (n + (s - info->stack->type), t); + strcat (n, s); + + free (info->stack->type); + info->stack->type = n; + + free (t); + + return true; +} + +/* Start adding a method to a class. */ + +static boolean +pr_class_start_method (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->stack != NULL); + info->stack->method = name; + return true; +} + +/* Add a variant to a method. */ + +static boolean +pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset, + context) + PTR p; + const char *physname; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; + bfd_vma voffset; + boolean context; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + char *context_type; + + assert (info->stack != NULL); + assert (info->stack->next != NULL); + + /* Put the const and volatile qualifiers on the type. */ + if (volatilep) + { + if (! append_type (info, " volatile")) + return false; + } + if (constp) + { + if (! append_type (info, " const")) + return false; + } + + /* Stick the name of the method into its type. */ + if (! substitute_type (info, + (context + ? info->stack->next->next->method + : info->stack->next->method))) + return false; + + /* Get the type. */ + method_type = pop_type (info); + if (method_type == NULL) + return false; + + /* Pull off the context type if there is one. */ + if (! context) + context_type = NULL; + else + { + context_type = pop_type (info); + if (context_type == NULL) + return false; + } + + /* Now the top of the stack is the class. */ + + if (! pr_fix_visibility (info, visibility)) + return false; + + if (! append_type (info, method_type) + || ! append_type (info, " /* ") + || ! append_type (info, physname) + || ! append_type (info, " ")) + return false; + if (context || voffset != 0) + { + char ab[20]; + + if (context) + { + if (! append_type (info, "context ") + || ! append_type (info, context_type) + || ! append_type (info, " ")) + return false; + } + print_vma (voffset, ab, true, false); + if (! append_type (info, "voffset ") + || ! append_type (info, ab)) + return false; + } + + return (append_type (info, " */;\n") + && indent_type (info)); +} + +/* Add a static variant to a method. */ + +static boolean +pr_class_static_method_variant (p, physname, visibility, constp, volatilep) + PTR p; + const char *physname; + enum debug_visibility visibility; + boolean constp; + boolean volatilep; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + + assert (info->stack != NULL); + assert (info->stack->next != NULL); + assert (info->stack->next->method != NULL); + + /* Put the const and volatile qualifiers on the type. */ + if (volatilep) + { + if (! append_type (info, " volatile")) + return false; + } + if (constp) + { + if (! append_type (info, " const")) + return false; + } + + /* Mark it as static. */ + if (! prepend_type (info, "static ")) + return false; + + /* Stick the name of the method into its type. */ + if (! substitute_type (info, info->stack->next->method)) + return false; + + /* Get the type. */ + method_type = pop_type (info); + if (method_type == NULL) + return false; + + /* Now the top of the stack is the class. */ + + if (! pr_fix_visibility (info, visibility)) + return false; + + return (append_type (info, method_type) + && append_type (info, " /* ") + && append_type (info, physname) + && append_type (info, " */;\n") + && indent_type (info)); +} + +/* Finish up a method. */ + +static boolean +pr_class_end_method (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + info->stack->method = NULL; + return true; +} + +/* Finish up a class. */ + +static boolean +pr_end_class_type (p) + PTR p; +{ + return pr_end_struct_type (p); +} + +/* Push a type on the stack using a typedef name. */ + +static boolean +pr_typedef_type (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, name); +} + +/* Push a type on the stack using a tag name. */ + +static boolean +pr_tag_type (p, name, id, kind) + PTR p; + const char *name; + unsigned int id; + enum debug_type_kind kind; +{ + struct pr_handle *info = (struct pr_handle *) p; + const char *t, *tag; + char idbuf[20]; + + switch (kind) + { + case DEBUG_KIND_STRUCT: + t = "struct "; + break; + case DEBUG_KIND_UNION: + t = "union "; + break; + case DEBUG_KIND_ENUM: + t = "enum "; + break; + case DEBUG_KIND_CLASS: + t = "class "; + break; + case DEBUG_KIND_UNION_CLASS: + t = "union class "; + break; + default: + abort (); + return false; + } + + if (! push_type (info, t)) + return false; + if (name != NULL) + tag = name; + else + { + sprintf (idbuf, "%%anon%u", id); + tag = idbuf; + } + + if (! append_type (info, tag)) + return false; + if (name != NULL && kind != DEBUG_KIND_ENUM) + { + sprintf (idbuf, " /* id %u */", id); + if (! append_type (info, idbuf)) + return false; + } + + return true; +} + +/* Output a typedef. */ + +static boolean +pr_typdef (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + if (! substitute_type (info, name)) + return false; + + s = pop_type (info); + if (s == NULL) + return false; +/* + indent (info); + TRACE_FPRINTF( (info->f, "typedef %s;\n", s)); +*/ + free (s); + + return true; +} + +/* Output a tag. The tag should already be in the string on the + stack, so all we have to do here is print it out. */ + +/*ARGSUSED*/ +static boolean +pr_tag (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + t = pop_type (info); + if (t == NULL) + return false; +/* + indent (info); + TRACE_FPRINTF( (info->f, "%s;\n", t)); +*/ + free (t); + + return true; +} + +/* Output an integer constant. */ + +static boolean +pr_int_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ +/* + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + indent (info); + print_vma (val, ab, false, false); + TRACE_FPRINTF( (info->f, "const int %s = %s;\n", name, ab)); + */ + return true; +} + +/* Output a floating point constant. */ + +static boolean +pr_float_constant (p, name, val) + PTR p; + const char *name; + double val; +{ +/* + struct pr_handle *info = (struct pr_handle *) p; + indent (info); + TRACE_FPRINTF( (info->f, "const double %s = %g;\n", name, val)); + */ + return true; +} + +/* Output a typed constant. */ + +static boolean +pr_typed_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + t = pop_type (info); + if (t == NULL) + return false; +/* + char ab[20]; + indent (info); + print_vma (val, ab, false, false); + TRACE_FPRINTF( (info->f, "const %s %s = %s;\n", t, name, ab)); +*/ + free (t); + + return true; +} + +/* Output a variable. */ + +static boolean +pr_variable (p, name, kind, val) + PTR p; + const char *name; + enum debug_var_kind kind; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + char ab[20]; + (void)ab; + + if (! substitute_type (info, name)) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + +#if 0 + indent (info); + switch (kind) + { + case DEBUG_STATIC: + case DEBUG_LOCAL_STATIC: + TRACE_FPRINTF( (info->f, "static ")); + break; + case DEBUG_REGISTER: + TRACE_FPRINTF( (info->f, "register ")); + break; + default: + break; + } + print_vma (val, ab, true, true); + TRACE_FPRINTF( (info->f, "%s /* %s */;\n", t, ab)); +#else /* 0 */ +#if 0 + if (kind==DEBUG_STATIC || kind==DEBUG_LOCAL_STATIC) { + print_vma (val, ab, true, true); + TRACE_FPRINTF( (info->f, "STATIC_VAR: %s /* %s */;\n", t, ab)); + } +#endif /* 0 */ +#endif /* !0 */ + + free (t); + + return true; +} + +/* Start outputting a function. */ + +static boolean +pr_start_function (p, name, global) + PTR p; + const char *name; + boolean global; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, name)) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + +#if 0 + indent (info); + if (! global) + TRACE_FPRINTF( (info->f, "static ")); + TRACE_FPRINTF( (info->f, "%s (", t)); + info->parameter = 1; +#else /* 0 */ + if (info->functions_size==info->functions_maxsize) { + info->functions_maxsize *= 2; + info->functions = xrealloc(info->functions, + info->functions_maxsize*sizeof(debug_function_t)); + assert(info->functions!=0); + } + /* info->functions[info->functions_size] = xmalloc(sizeof(debug_function_t)); */ + info->function = &info->functions[info->functions_size]; + ++info->functions_size; + info->function->symbol = NULL; + info->function->lines = NULL; + info->function->lines_count = 0; + info->function->max_lines_count = 0; + info->function->name = t; + info->function->filename = NULL; + info->function->block = NULL; + info->function->argv = NULL; + info->function->argc = 0; + info->function->max_argc = 0; +#endif /* !0 */ + return true; +} + +/* Output a function parameter. */ + +static boolean +pr_function_parameter (p, name, kind, val) + PTR p; + const char *name; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + debug_function_t* f = info->function; + char *t; + char ab[20]; + (void)ab; + + if (kind == DEBUG_PARM_REFERENCE + || kind == DEBUG_PARM_REF_REG) + { + if (! pr_reference_type (p)) + return false; + } + + if (! substitute_type (info, name)) + return false; + + t = pop_type (info); + if (t == NULL) + return false; + +#if 0 + if (info->parameter != 1) + TRACE_FPRINTF( (info->f, ", ")); + + if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG) + TRACE_FPRINTF( (info->f, "register ")); + + print_vma (val, ab, true, true); + TRACE_FPRINTF( (info->f, "%s /* %s */", t, ab)); + free (t); + ++info->parameter; +#else /* 0 */ + assert(f!=NULL); + if (f->argv==NULL) { + f->max_argc = 7; /* rarely anyone has more than that many args... */ + f->argv = xmalloc(sizeof(debug_parameter_t)*f->max_argc); + } else if (f->argc==f->max_argc) { + f->max_argc *= 2; + f->argv = realloc(f->argv,sizeof(debug_parameter_t)*f->max_argc); + } + f->argv[f->argc].offset = val; + f->argv[f->argc].name = t; + ++f->argc; +#endif /* !0 */ + return true; +} + +/* Start writing out a block. */ + +static boolean +pr_start_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + debug_block_t* block = 0; + (void)ab; +#if 0 + if (info->parameter > 0) + { + TRACE_FPRINTF( (info->f, ")\n")); + info->parameter = 0; + } + indent (info); + print_vma (addr, ab, true, true); + TRACE_FPRINTF( (info->f, "{ /* %s */\n", ab)); + info->indent += 2; +#else + if (info->block) { + if (info->block->childs_count==0) + info->block->childs = xmalloc(sizeof(debug_block_t)); + else + info->block->childs = xrealloc(info->block->childs, + info->block->childs_count*sizeof(debug_block_t)); + block = &info->block->childs[info->block->childs_count]; + } else { + block = xmalloc(sizeof(debug_block_t)); + info->function->block = block; + } + block->begin_addr = addr; + block->end_addr = 0; + block->parent = info->block; + block->childs = NULL; + block->childs_count = 0; + info->block = block; +#endif + return true; +} + +/* Write out line number information. */ + +static boolean +pr_lineno (p, filename, lineno, addr) + PTR p; + const char *filename; + unsigned long lineno; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + debug_function_t* f = info->function; + (void)ab; + +#if 0 + indent (info); + print_vma (addr, ab, true, true); + TRACE_FPRINTF( (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab)); +#else /* 0 */ + if (f==NULL) /* FIXME: skips junk silently. */ + return true; + /* assert(f!=NULL); */ + if (f->filename==NULL) { + f->filename = filename; + assert(f->lines==0); + f->max_lines_count = 4; + f->lines = xmalloc(sizeof(debug_lineno_t)*f->max_lines_count); + } + if (f->lines_count==f->max_lines_count) { + f->max_lines_count *= 2; + f->lines = xrealloc(f->lines, sizeof(debug_lineno_t)*f->max_lines_count); + } + f->lines[f->lines_count].lineno = lineno; + f->lines[f->lines_count].addr = addr; + ++f->lines_count; +#endif /* !0 */ + + return true; +} + +/* Finish writing out a block. */ + +static boolean +pr_end_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + +#if 0 + char ab[20]; + + info->indent -= 2; + indent (info); + print_vma (addr, ab, true, true); + TRACE_FPRINTF( (info->f, "} /* %s */\n", ab)); +#else /* 0 */ + assert(info->block!=0); + info->block->end_addr = addr; + info->block = info->block->parent; +#endif /* !0 */ + + return true; +} + +/* Finish writing out a function. */ + +/*ARGSUSED*/ +static boolean +pr_end_function (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + assert(info->block==0); + info->function = NULL; + return true; +} + +/* third parameter to segv_action. */ +/* Got it after a bit of head scratching and stack dumping. */ +typedef struct { + u_int32_t foo1; /* +0x00 */ + u_int32_t foo2; + u_int32_t foo3; + u_int32_t foo4; /* usually 2 */ + u_int32_t foo5; /* +0x10 */ + u_int32_t xgs; /* always zero */ + u_int32_t xfs; /* always zero */ + u_int32_t xes; /* always es=ds=ss */ + u_int32_t xds; /* +0x20 */ + u_int32_t edi; + u_int32_t esi; + u_int32_t ebp; + u_int32_t esp; /* +0x30 */ + u_int32_t ebx; + u_int32_t edx; + u_int32_t ecx; + u_int32_t eax; /* +0x40 */ + u_int32_t foo11; /* usually 0xe */ + u_int32_t foo12; /* usually 0x6 */ + u_int32_t eip; /* instruction pointer */ + u_int32_t xcs; /* +0x50 */ + u_int32_t foo21; /* usually 0x2 */ + u_int32_t foo22; /* second stack pointer?! Probably. */ + u_int32_t xss; + u_int32_t foo31; /* +0x60 */ /* usually 0x0 */ + u_int32_t foo32; /* usually 0x2 */ + u_int32_t fault_addr; /* Address which caused a fault */ + u_int32_t foo41; /* usually 0x2 */ +} signal_regs_t; + +signal_regs_t* ptrace_regs = 0; /* Tells my_ptrace to "ptrace" current process" */ +/* + * my_ptrace: small wrapper around ptrace. + * Act as normal ptrace if ptrace_regs==0. + * Read data from current process if ptrace_regs!=0. + */ +static int +my_ptrace( int request, + int pid, + int addr, + int data) +{ + if (ptrace_regs==0) + return ptrace(request, pid, addr, data); + /* we are tracing ourselves! */ + switch (request) { + case PTRACE_ATTACH: return 0; + case PTRACE_CONT: return 0; + case PTRACE_DETACH: return 0; + case PTRACE_PEEKUSER: + switch (addr / 4) { + case EIP: return ptrace_regs->eip; + case EBP: return ptrace_regs->ebp; + default: assert(0); + } + case PTRACE_PEEKTEXT: /* FALLTHROUGH */ + case PTRACE_PEEKDATA: return *(int*)(addr); + default: assert(0); + } + errno = 1; /* what to do here? */ + return 1; /* failed?! */ +} + +#define MAXARGS 6 + +/* + * To minimize the number of parameters. + */ +typedef struct { + asymbol** syms; /* Sorted! */ + int symcount; + debug_function_t** functions; + int functions_size; +} symbol_data_t; + +/* + * Perform a search. A binary search for a symbol. + */ +static void +decode_symbol( symbol_data_t* symbol_data, + const unsigned long addr, + char* buf, + const int bufsize) +{ + asymbol** syms = symbol_data->syms; + const int symcount = symbol_data->symcount; + int bottom = 0; + int top = symcount - 1; + int i; + if (symcount==0) { + sprintf(buf, "????"); + return; + } + while (top>bottom+1) { + i = (top+bottom) / 2; + if (bfd_asymbol_value(syms[i])==addr) { + sprintf(buf, "%s", syms[i]->name); + return; + } else if (bfd_asymbol_value(syms[i]) > addr) + top = i; + else + bottom = i; + } + i = bottom; + if (addr<bfd_asymbol_value(syms[i]) || addr>(syms[i]->section->vma+syms[i]->section->_cooked_size)) + sprintf(buf, "????"); + else + sprintf(buf, "%s + 0x%lx", syms[i]->name, addr-bfd_asymbol_value(syms[i])); +} + +/* + * 1. Perform a binary search for an debug_function_t. + * 2. Fill buf/bufsize with name, parameters and lineno, if found + * Or with '????' otherwise. + */ +static debug_function_t* +find_debug_function_t( symbol_data_t* symbol_data, + const pid_t pid, + const unsigned long fp, /* frame pointer */ + const unsigned long addr, + char* buf, /* string buffer */ + const int bufsize)/* FIXME: not used! */ +{ + debug_function_t** syms = symbol_data->functions; + debug_function_t* f = NULL; + debug_block_t* block = NULL; + debug_lineno_t* lineno = NULL; + const int symcount = symbol_data->functions_size; + int bottom = 0; + int top = symcount - 1; + int i; + char* bufptr = buf; + + if (symcount==0) { + sprintf(buf, "????"); + return NULL; + } + while (top>bottom+1) { + i = (top+bottom) / 2; + if (syms[i]->block->begin_addr==addr) { + f = syms[i]; + break; + } else if (syms[i]->block->begin_addr > addr) + top = i; + else + if (syms[i]->block->end_addr >= addr) { + f = syms[i]; + break; + } else + bottom = i; + } + i = bottom; + if (f!=0) + block = f->block; + else { + block = syms[i]->block; + if (block->begin_addr>=addr && block->end_addr<=addr) + f = syms[i]; + } + if (f==0) + sprintf(buf, "????"); + else { + /* + * Do the backtrace the GDB way... + */ + unsigned long arg; + /* assert(f->lines_count>0); */ + if (f->lines_count>0) { + lineno = &f->lines[f->lines_count-1]; + for (i=1; i<f->lines_count; ++i) + if (f->lines[i].addr>addr) { + lineno = &f->lines[i-1]; + break; + } + } + bufptr[0] = 0; + bufptr += sprintf(bufptr, "%s+0x%lx (", f->name, addr-block->begin_addr); + for (i=0; i<f->argc; ++i) { + bufptr += sprintf(bufptr, "%s = ", f->argv[i].name); + /* FIXME: better parameter printing */ + errno = 0; + arg = my_ptrace(PTRACE_PEEKDATA, pid, fp+f->argv[i].offset, 0); + assert(errno==0); + bufptr += sprintf(bufptr, "0x%x", arg); + if (i!=f->argc-1) + bufptr += sprintf(bufptr, ", "); + } + if (lineno!=0) + bufptr += sprintf(bufptr, ") at %s:%d", f->filename, lineno->lineno); + } + return f; +} + +/* + * Advance through the stacks and display frames as needed. + */ +static int +my_crawl( int pid, + symbol_data_t* symbol_data, + int fout) +{ + unsigned long pc = 0; + unsigned long fp = 0; + unsigned long nextfp; + unsigned long nargs; + unsigned long i; + unsigned long arg; + char buf[8096]; // FIXME: enough? + debug_function_t* f = 0; + + errno = 0; + + pc = my_ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0); + if (!errno) + fp = my_ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0); + + if (!errno) { +#if 1 + f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); + fdprintf(fout,"0x%08lx: %s", pc, buf); + for ( ; !errno && fp; ) { + nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); + if (errno) + break; + + if (f==0) { + nargs = (nextfp - fp - 8) / 4; + if (nargs > MAXARGS) + nargs = MAXARGS; + if (nargs > 0) { + fdputs(" (", fout); + for (i = 1; i <= nargs; i++) { + arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); + if (errno) + break; + fdprintf(fout,"%lx", arg); + if (i < nargs) + fdputs(", ", fout); + } + fdputc(')', fout); + nargs = nextfp - fp - 8 - (4 * nargs); + if (!errno && nargs > 0) + fdprintf(fout," + %lx\n", nargs); + else + fdputc('\n', fout); + } else + fdputc('\n', fout); + } else + fdputc('\n', fout); + + if (errno || !nextfp) + break; + pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); + fp = nextfp; + if (errno) + break; + f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); + fdprintf(fout,"0x%08lx: %s", pc, buf); + } +#else /* 1 */ + decode_symbol(symbol_data, pc, buf, sizeof(buf)); + fdprintf(fout,"0x%08lx: %s", pc, buf); + for ( ; !errno && fp; ) { + nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); + if (errno) + break; + + nargs = (nextfp - fp - 8) / 4; + if (nargs > MAXARGS) + nargs = MAXARGS; + if (nargs > 0) { + fputs(" (", fout); + for (i = 1; i <= nargs; i++) { + arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); + if (errno) + break; + fdprintf(fout,"%lx", arg); + if (i < nargs) + fputs(", ", fout); + } + fdputc(')', fout); + nargs = nextfp - fp - 8 - (4 * nargs); + if (!errno && nargs > 0) + fdprintf(fout," + %lx\n", nargs); + else + fdputc('\n', fout); + } else + fdputc('\n', fout); + + if (errno || !nextfp) + break; + pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); + fp = nextfp; + if (errno) + break; + decode_symbol(symbol_data, pc, buf, sizeof(buf)); + fdprintf(fout,"0x%08lx: %s", pc, buf); + } +#endif /* !1 */ + } + if (errno) + perror("my_crawl"); + return errno; +} + +/* layout from /usr/src/linux/arch/i386/kernel/process.c */ +static void +show_regs( signal_regs_t* regs, + int fd) +{ + /* long cr0 = 0L, cr2 = 0L, cr3 = 0L; */ + + fdprintf(fd,"\n"); + fdprintf(fd,"FAULT ADDR: %08x\n", regs->fault_addr); + fdprintf(fd,"EIP: %04x:[<%08x>]",0xffff & regs->xcs,regs->eip); + if (regs->xcs & 3) + fdprintf(fd," ESP: %04x:%08x",0xffff & regs->xss,regs->esp); + /*fdprintf(fd," EFLAGS: %08lx\n",regs->eflags); */ + fdprintf(fd, "\n"); + fdprintf(fd,"EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n", + regs->eax,regs->ebx,regs->ecx,regs->edx); + fdprintf(fd,"ESI: %08x EDI: %08x EBP: %08x", + regs->esi, regs->edi, regs->ebp); + fdprintf(fd," DS: %04x ES: %04x\n", + 0xffff & regs->xds,0xffff & regs->xes); + /* + __asm__("movl %%cr0, %0": "=r" (cr0)); + __asm__("movl %%cr2, %0": "=r" (cr2)); + __asm__("movl %%cr3, %0": "=r" (cr3)); + fprintf(stderr,"CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); */ +} + +/* + * Load a BFD for an executable based on PID. Return 0 on failure. + */ +static bfd* +load_bfd( const int pid) +{ + char filename[512]; + bfd* abfd = 0; + + /* Get the contents from procfs. */ +#if 1 + sprintf(filename, "/proc/%d/exe", pid); +#else + sprintf(filename, "crashing"); +#endif + + if ((abfd = bfd_openr (filename, 0))== NULL) + bfd_nonfatal (filename); + else { + char** matching; + assert(bfd_check_format(abfd, bfd_archive)!=true); + + /* + * There is no indication in BFD documentation that it should be done. + * God knows why... + */ + if (!bfd_check_format_matches (abfd, bfd_object, &matching)) { + bfd_nonfatal (bfd_get_filename (abfd)); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) { + list_matching_formats (matching); + free (matching); + } + } + } + return abfd; +} + +/* + * Those are for qsort. We need only function addresses, so all the others don't count. + */ +/* + * Compare two BFD::asymbol-s. + */ +static int +compare_symbols(const void* ap, + const void* bp) +{ + const asymbol *a = *(const asymbol **)ap; + const asymbol *b = *(const asymbol **)bp; + if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) + return 1; + else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) + return -1; + return 0; +} + +/* + * Compare two debug_asymbol_t-s. + */ +static int +compare_debug_function_t(const void* ap, + const void* bp) +{ + const debug_function_t *a = *(const debug_function_t **)ap; + const debug_function_t *b = *(const debug_function_t **)bp; + assert(a->block!=0); + assert(b->block!=0); + { + const bfd_vma addr1 = a->block->begin_addr; + const bfd_vma addr2 = b->block->begin_addr; + if (addr1 > addr2) + return 1; + else if (addr2 > addr1) + return -1; + } + return 0; +} + +/* + * Filter out (in place) symbols that are useless for stack tracing. + * COUNT is the number of elements in SYMBOLS. + * Return the number of useful symbols. + */ + +static long +remove_useless_symbols( asymbol** symbols, + long count) +{ + asymbol** in_ptr = symbols; + asymbol** out_ptr = symbols; + + while (--count >= 0) { + asymbol *sym = *in_ptr++; + + if (sym->name == NULL || sym->name[0] == '\0' || sym->value==0) + continue; + if (sym->flags & (BSF_DEBUGGING)) + continue; + if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) + continue; + *out_ptr++ = sym; + } + return out_ptr - symbols; +} + +/* + * Debugging information. + */ +static bfd* abfd = 0; +static PTR dhandle = 0; +static asymbol** syms = 0; +static long symcount = 0; +static asymbol** sorted_syms = 0; +static long sorted_symcount = 0; +static debug_function_t** functions = 0; +static int functions_size = 0; +static int sigreport = SIGUSR1; +static pthread_t segv_tid; /* What thread did SEGV? */ +static pid_t segv_pid; + +/* + * We'll get here after a SIGSEGV. But you can install it on other signals, too :) + * Because we are in the middle of the SIGSEGV, we are on our own. We can't do + * any malloc(), any fopen(), nothing. The last is actually a sin. We event can't + * fprintf(stderr,...)!!! + */ +static void +segv_action(int signo, siginfo_t* siginfo, void* ptr) +{ + symbol_data_t symbol_data; + int fd = -1; + + segv_pid = getpid(); + segv_tid = pthread_self(); + fd = open_log_file(segv_tid, segv_pid); + /* signal(SIGSEGV, SIG_DFL); */ + ptrace_regs = (signal_regs_t*)ptr; + assert(ptrace_regs!=0); + + /* Show user how guilty we are. */ + fdprintf(fd,"--------- SEGV in PROCESS %d, THREAD %d ---------------\n", segv_pid, pthread_self()); + show_regs(ptrace_regs, fd); + + /* Some form of stack trace, too. */ + fdprintf(fd, "STACK TRACE:\n"); + + symbol_data.syms = sorted_syms; + symbol_data.symcount = sorted_symcount; + symbol_data.functions = functions; + symbol_data.functions_size = functions_size; + my_crawl(segv_pid, &symbol_data, fd); + //fflush(stdout); + close(fd); + linuxthreads_notify_others(sigreport); +} + + +static void +report_action(int signo, siginfo_t* siginfo, void* ptr) +{ + const int pid = getpid(); + pthread_t tid = pthread_self(); + symbol_data_t symbol_data; + int fd; + if (pthread_equal(tid, segv_tid)) { + /* We have already printed our stack trace... */ + return; + } + + fd = open_log_file(tid, pid); + fdprintf(fd, "REPORT: CURRENT PROCESS:%d, THREAD:%d\n", getpid(), pthread_self()); + /* signal(SIGSEGV, SIG_DFL); */ + ptrace_regs = (signal_regs_t*)ptr; + assert(ptrace_regs!=0); + + /* Show user how guilty we are. */ + fdprintf(fd,"--------- STACK TRACE FOR PROCESS %d, THREAD %d ---------------\n", pid, pthread_self()); + show_regs(ptrace_regs, fd); + + /* Some form of stack trace, too. */ + fdprintf(fd, "STACK TRACE:\n"); + + symbol_data.syms = sorted_syms; + symbol_data.symcount = sorted_symcount; + symbol_data.functions = functions; + symbol_data.functions_size = functions_size; + my_crawl(pid, &symbol_data, fd); + //fflush(stdout); + close(fd); + /* Tell segv_thread to proceed after pause(). */ + /*pthread_kill(segv_tid, sigreport); + kill(segv_pid, sigreport); + pthread_cancel(tid); */ +} + +/* + * Main library routine. Just call it on your program. + */ +int +pstack_install_segv_action( const char* path_format_) +{ + const int pid = getpid(); + struct sigaction act; + + /* Store what we have to for later usage. */ + path_format = path_format_; + + /* We need a signal action for SIGSEGV and sigreport ! */ + sigreport = SIGUSR1; + act.sa_handler = 0; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO|SA_ONESHOT; /* Just one SIGSEGV. */ + act.sa_sigaction = segv_action; + act.sa_restorer = NULL; + if (sigaction(SIGSEGV, &act, NULL)!=0) { + perror("sigaction"); + return 1; + } + act.sa_sigaction = report_action; + act.sa_flags = SA_SIGINFO; /* But many sigreports. */ + if (sigaction(sigreport, &act, NULL)!=0) { + perror("sigaction"); + return 1; + } + + /* And a little setup for libiberty. */ + program_name = "crashing"; + xmalloc_set_program_name (program_name); + + /* Umm, and initialize BFD, too */ + bfd_init(); +#if 0 + list_supported_targets(0, stdout); + set_default_bfd_target(); +#endif /* 0 */ + + if ((abfd = load_bfd(pid))==0) + fprintf(stderr, "BFD load failed..\n"); + else { + long storage_needed = bfd_get_symtab_upper_bound (abfd); + long i; + (void)i; + + if (storage_needed < 0) + fprintf(stderr, "Symbol table size estimation failure.\n"); + else if (storage_needed > 0) { + syms = (asymbol **) xmalloc (storage_needed); + symcount = bfd_canonicalize_symtab (abfd, syms); + + TRACE_FPRINTF((stderr, "TOTAL: %ld SYMBOLS.\n", symcount)); + /* We need debugging info, too! */ + if (symcount==0 || (dhandle = read_debugging_info (abfd, syms, symcount))==0) + fprintf(stderr, "NO DEBUGGING INFORMATION FOUND.\n"); + + /* We make a copy of syms to sort. We don't want to sort syms + because that will screw up the relocs. */ + sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); + memcpy (sorted_syms, syms, symcount * sizeof (asymbol *)); + +#if 0 + for (i=0; i<symcount; ++i) + if (syms[i]->name!=0 && strlen(syms[i]->name)>0 && syms[i]->value!=0) + printf("%08lx T %s\n", syms[i]->section->vma + syms[i]->value, syms[i]->name); +#endif + sorted_symcount = remove_useless_symbols (sorted_syms, symcount); + TRACE_FPRINTF((stderr, "SORTED: %ld SYMBOLS.\n", sorted_symcount)); + + /* Sort the symbols into section and symbol order */ + qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); +#if 0 + for (i=0; i<sorted_symcount; ++i) + if (sorted_syms[i]->name!=0 && strlen(sorted_syms[i]->name)>0 && sorted_syms[i]->value!=0) + printf("%08lx T %s\n", sorted_syms[i]->section->vma + sorted_syms[i]->value, sorted_syms[i]->name); +#endif + /* We have symbols, we need debugging info somehow sorted out. */ + if (dhandle==0) { + fprintf(stderr, "STACK TRACE WILL BE UNCOMFORTABLE.\n"); + } else { + /* Start collecting the debugging information.... */ + struct pr_handle info; + + info.f = stdout; + info.indent = 0; + info.stack = NULL; + info.parameter = 0; + info.block = NULL; + info.function = NULL; + info.functions_size = 0; + info.functions_maxsize = 1000; + info.functions = (debug_function_t*)xmalloc(sizeof(debug_function_t)*info.functions_maxsize); + debug_write (dhandle, &pr_fns, (PTR) &info); + TRACE_FPRINTF((stdout, "\n%d DEBUG SYMBOLS\n", info.functions_size)); + assert(info.functions_size!=0); + functions = xmalloc(sizeof(debug_function_t*)*info.functions_size); + functions_size = info.functions_size; + for (i=0; i<functions_size; ++i) + functions[i] = &info.functions[i]; + /* Sort the symbols into section and symbol order */ + qsort (functions, functions_size, sizeof(debug_function_t*), + compare_debug_function_t); +#if 0 + for (i=0; i<info.functions_size; ++i) + fprintf(stdout, "%08lx T %s\n", info.functions[i].block->begin_addr, info.functions[i].name); +#endif + fflush(stdout); + } + } else /* storage_needed == 0 */ + fprintf(stderr, "NO SYMBOLS FOUND.\n"); + } + return 0; +} + +/*********************************************************************/ +/*********************************************************************/ +/*********************************************************************/ + diff --git a/pstack/pstack.h b/pstack/pstack.h new file mode 100644 index 00000000000..4c4fad7e754 --- /dev/null +++ b/pstack/pstack.h @@ -0,0 +1,22 @@ +/* $Header$ */ + +#ifndef pstack_pstack_h_ +#define pstack_pstack_h_ + +#include "pstacktrace.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Install the stack-trace-on-SEGV handler.... + */ +extern int +pstack_install_segv_action( const char* path_format); +#ifdef __cplusplus +} +#endif + +#endif /* pstack_pstack_h_ */ + diff --git a/pstack/pstacktrace.h b/pstack/pstacktrace.h new file mode 100644 index 00000000000..c884bcb9f87 --- /dev/null +++ b/pstack/pstacktrace.h @@ -0,0 +1,24 @@ +/* $Header$ */ + +/* + * Debugging macros. + */ + +#ifndef pstacktrace_h_ +#define pstacktrace_h_ + +#define PSTACK_DEBUG 1 +#undef PSTACK_DEBUG + +#ifdef PSTACK_DEBUG +# define TRACE_PUTC(a) putc a +# define TRACE_FPUTS(a) fputs a +# define TRACE_FPRINTF(a) fprintf a +#else /* PSTACK_DEBUG */ +# define TRACE_PUTC(a) (void)0 +# define TRACE_FPUTS(a) (void)0 +# define TRACE_FPRINTF(a) (void)0 +#endif /* !PSTACK_DEBUG */ + +#endif /* pstacktrace_h_ */ + diff --git a/pstack/rddbg.c b/pstack/rddbg.c new file mode 100644 index 00000000000..be3dfc21c57 --- /dev/null +++ b/pstack/rddbg.c @@ -0,0 +1,462 @@ +/* rddbg.c -- Read debugging information into a generic form. + Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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. */ + +/* This file reads debugging information into a generic form. This + file knows how to dig the debugging information out of an object + file. */ + +#include <bfd.h> +#include "bucomm.h" +#include <libiberty.h> +#include "debug.h" +#include "budbg.h" + +static boolean read_section_stabs_debugging_info + PARAMS ((bfd *, asymbol **, long, PTR, boolean *)); +static boolean read_symbol_stabs_debugging_info + PARAMS ((bfd *, asymbol **, long, PTR, boolean *)); +static boolean read_ieee_debugging_info PARAMS ((bfd *, PTR, boolean *)); +static void save_stab PARAMS ((int, int, bfd_vma, const char *)); +static void stab_context PARAMS ((void)); +static void free_saved_stabs PARAMS ((void)); + +/* Read debugging information from a BFD. Returns a generic debugging + pointer. */ + +PTR +read_debugging_info (abfd, syms, symcount) + bfd *abfd; + asymbol **syms; + long symcount; +{ + PTR dhandle; + boolean found; + + dhandle = debug_init (); + if (dhandle == NULL) + return NULL; + + if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, + &found)) + return NULL; + + if (bfd_get_flavour (abfd) == bfd_target_aout_flavour) + { + if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, + &found)) + return NULL; + } + + if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour) + { + if (! read_ieee_debugging_info (abfd, dhandle, &found)) + return NULL; + } + + /* Try reading the COFF symbols if we didn't find any stabs in COFF + sections. */ + if (! found + && bfd_get_flavour (abfd) == bfd_target_coff_flavour + && symcount > 0) + { +#if 0 +/* + * JZ: Do we need coff? + */ + if (! parse_coff (abfd, syms, symcount, dhandle)) +#else + fprintf (stderr, "%s: COFF support temporarily disabled\n", + bfd_get_filename (abfd)); + return NULL; +#endif + return NULL; + found = true; + } + + if (! found) + { + fprintf (stderr, "%s: no recognized debugging information\n", + bfd_get_filename (abfd)); + return NULL; + } + + return dhandle; +} + +/* Read stabs in sections debugging information from a BFD. */ + +static boolean +read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) + bfd *abfd; + asymbol **syms; + long symcount; + PTR dhandle; + boolean *pfound; +{ + static struct + { + const char *secname; + const char *strsecname; + } names[] = { { ".stab", ".stabstr" } }; + unsigned int i; + PTR shandle; + + *pfound = false; + shandle = NULL; + + for (i = 0; i < sizeof names / sizeof names[0]; i++) + { + asection *sec, *strsec; + + sec = bfd_get_section_by_name (abfd, names[i].secname); + strsec = bfd_get_section_by_name (abfd, names[i].strsecname); + if (sec != NULL && strsec != NULL) + { + bfd_size_type stabsize, strsize; + bfd_byte *stabs, *strings; + bfd_byte *stab; + bfd_size_type stroff, next_stroff; + + stabsize = bfd_section_size (abfd, sec); + stabs = (bfd_byte *) xmalloc (stabsize); + if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize)) + { + fprintf (stderr, "%s: %s: %s\n", + bfd_get_filename (abfd), names[i].secname, + bfd_errmsg (bfd_get_error ())); + return false; + } + + strsize = bfd_section_size (abfd, strsec); + strings = (bfd_byte *) xmalloc (strsize); + if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize)) + { + fprintf (stderr, "%s: %s: %s\n", + bfd_get_filename (abfd), names[i].strsecname, + bfd_errmsg (bfd_get_error ())); + return false; + } + + if (shandle == NULL) + { + shandle = start_stab (dhandle, abfd, true, syms, symcount); + if (shandle == NULL) + return false; + } + + *pfound = true; + + stroff = 0; + next_stroff = 0; + for (stab = stabs; stab < stabs + stabsize; stab += 12) + { + bfd_size_type strx; + int type; + int other; + int desc; + bfd_vma value; + + /* This code presumes 32 bit values. */ + + strx = bfd_get_32 (abfd, stab); + type = bfd_get_8 (abfd, stab + 4); + other = bfd_get_8 (abfd, stab + 5); + desc = bfd_get_16 (abfd, stab + 6); + value = bfd_get_32 (abfd, stab + 8); + + if (type == 0) + { + /* Special type 0 stabs indicate the offset to the + next string table. */ + stroff = next_stroff; + next_stroff += value; + } + else + { + char *f, *s; + + f = NULL; + s = (char *) strings + stroff + strx; + while (s[strlen (s) - 1] == '\\' + && stab + 12 < stabs + stabsize) + { + char *p; + + stab += 12; + p = s + strlen (s) - 1; + *p = '\0'; + s = concat (s, + ((char *) strings + + stroff + + bfd_get_32 (abfd, stab)), + (const char *) NULL); + + /* We have to restore the backslash, because, if + the linker is hashing stabs strings, we may + see the same string more than once. */ + *p = '\\'; + + if (f != NULL) + free (f); + f = s; + } + + save_stab (type, desc, value, s); + + if (! parse_stab (dhandle, shandle, type, desc, value, s)) + { +#if 0 +/* + * JZ: skip the junk. + */ + stab_context (); + free_saved_stabs (); + return false; +#endif + } + + /* Don't free f, since I think the stabs code + expects strings to hang around. This should be + straightened out. FIXME. */ + } + } + + free_saved_stabs (); + free (stabs); + + /* Don't free strings, since I think the stabs code expects + the strings to hang around. This should be straightened + out. FIXME. */ + } + } + + if (shandle != NULL) + { + if (! finish_stab (dhandle, shandle)) + return false; + } + + return true; +} + +/* Read stabs in the symbol table. */ + +static boolean +read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) + bfd *abfd; + asymbol **syms; + long symcount; + PTR dhandle; + boolean *pfound; +{ + PTR shandle; + asymbol **ps, **symend; + + shandle = NULL; + symend = syms + symcount; + for (ps = syms; ps < symend; ps++) + { + symbol_info i; + + bfd_get_symbol_info (abfd, *ps, &i); + + if (i.type == '-') + { + const char *s; + char *f; + + if (shandle == NULL) + { + shandle = start_stab (dhandle, abfd, false, syms, symcount); + if (shandle == NULL) + return false; + } + + *pfound = true; + + s = i.name; + f = NULL; + while (s[strlen (s) - 1] == '\\' + && ps + 1 < symend) + { + char *sc, *n; + + ++ps; + sc = xstrdup (s); + sc[strlen (sc) - 1] = '\0'; + n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL); + free (sc); + if (f != NULL) + free (f); + f = n; + s = n; + } + + save_stab (i.stab_type, i.stab_desc, i.value, s); + + if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc, + i.value, s)) + { + stab_context (); + free_saved_stabs (); + return false; + } + + /* Don't free f, since I think the stabs code expects + strings to hang around. This should be straightened out. + FIXME. */ + } + } + + free_saved_stabs (); + + if (shandle != NULL) + { + if (! finish_stab (dhandle, shandle)) + return false; + } + + return true; +} + +/* Read IEEE debugging information. */ + +static boolean +read_ieee_debugging_info (abfd, dhandle, pfound) + bfd *abfd; + PTR dhandle; + boolean *pfound; +{ + asection *dsec; + bfd_size_type size; + bfd_byte *contents; + + /* The BFD backend puts the debugging information into a section + named .debug. */ + + dsec = bfd_get_section_by_name (abfd, ".debug"); + if (dsec == NULL) + return true; + + size = bfd_section_size (abfd, dsec); + contents = (bfd_byte *) xmalloc (size); + if (! bfd_get_section_contents (abfd, dsec, contents, 0, size)) + return false; + + if (! parse_ieee (dhandle, abfd, contents, size)) + return false; + + free (contents); + + *pfound = true; + + return true; +} + +/* Record stabs strings, so that we can give some context for errors. */ + +#define SAVE_STABS_COUNT (16) + +struct saved_stab +{ + int type; + int desc; + bfd_vma value; + char *string; +}; + +static struct saved_stab saved_stabs[SAVE_STABS_COUNT]; +static int saved_stabs_index; + +/* Save a stabs string. */ + +static void +save_stab (type, desc, value, string) + int type; + int desc; + bfd_vma value; + const char *string; +{ + if (saved_stabs[saved_stabs_index].string != NULL) + free (saved_stabs[saved_stabs_index].string); + saved_stabs[saved_stabs_index].type = type; + saved_stabs[saved_stabs_index].desc = desc; + saved_stabs[saved_stabs_index].value = value; + saved_stabs[saved_stabs_index].string = xstrdup (string); + saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT; +} + +/* Provide context for an error. */ + +static void +stab_context () +{ + int i; + + fprintf (stderr, "Last stabs entries before error:\n"); + fprintf (stderr, "n_type n_desc n_value string\n"); + + i = saved_stabs_index; + do + { + struct saved_stab *stabp; + + stabp = saved_stabs + i; + if (stabp->string != NULL) + { + const char *s; + + s = bfd_get_stab_name (stabp->type); + if (s != NULL) + fprintf (stderr, "%-6s", s); + else if (stabp->type == 0) + fprintf (stderr, "HdrSym"); + else + fprintf (stderr, "%-6d", stabp->type); + fprintf (stderr, " %-6d ", stabp->desc); + fprintf_vma (stderr, stabp->value); + if (stabp->type != 0) + fprintf (stderr, " %s", stabp->string); + fprintf (stderr, "\n"); + } + i = (i + 1) % SAVE_STABS_COUNT; + } + while (i != saved_stabs_index); +} + +/* Free the saved stab strings. */ + +static void +free_saved_stabs () +{ + int i; + + for (i = 0; i < SAVE_STABS_COUNT; i++) + { + if (saved_stabs[i].string != NULL) + { + free (saved_stabs[i].string); + saved_stabs[i].string = NULL; + } + } + + saved_stabs_index = 0; +} diff --git a/pstack/stabs.c b/pstack/stabs.c new file mode 100644 index 00000000000..076231d19cb --- /dev/null +++ b/pstack/stabs.c @@ -0,0 +1,5082 @@ +/* stabs.c -- Parse stabs debugging information + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Written by Ian Lance Taylor <ian@cygnus.com>. + + This file is part of GNU Binutils. + + 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. */ + +/* This file contains code which parses stabs debugging information. + The organization of this code is based on the gdb stabs reading + code. The job it does is somewhat different, because it is not + trying to identify the correct address for anything. */ + +#include <stdio.h> +#include <ctype.h> + +#include <bfd.h> +#include "bucomm.h" +#include <libiberty.h> +#include "demangle.h" +#include "debug.h" +#include "budbg.h" + +/* Meaningless definition needs by aout64.h. FIXME. */ +#define BYTES_IN_WORD 4 + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" + +/* The number of predefined XCOFF types. */ + +#define XCOFF_TYPE_COUNT 34 + +/* This structure is used as a handle so that the stab parsing doesn't + need to use any static variables. */ + +struct stab_handle +{ + /* The BFD. */ + bfd *abfd; + /* True if this is stabs in sections. */ + boolean sections; + /* The symbol table. */ + asymbol **syms; + /* The number of symbols. */ + long symcount; + /* The accumulated file name string. */ + char *so_string; + /* The value of the last N_SO symbol. */ + bfd_vma so_value; + /* The value of the start of the file, so that we can handle file + relative N_LBRAC and N_RBRAC symbols. */ + bfd_vma file_start_offset; + /* The offset of the start of the function, so that we can handle + function relative N_LBRAC and N_RBRAC symbols. */ + bfd_vma function_start_offset; + /* The version number of gcc which compiled the current compilation + unit, 0 if not compiled by gcc. */ + int gcc_compiled; + /* Whether an N_OPT symbol was seen that was not generated by gcc, + so that we can detect the SunPRO compiler. */ + boolean n_opt_found; + /* The main file name. */ + char *main_filename; + /* A stack of unfinished N_BINCL files. */ + struct bincl_file *bincl_stack; + /* A list of finished N_BINCL files. */ + struct bincl_file *bincl_list; + /* Whether we are inside a function or not. */ + boolean within_function; + /* The address of the end of the function, used if we have seen an + N_FUN symbol while in a function. This is -1 if we have not seen + an N_FUN (the normal case). */ + bfd_vma function_end; + /* The depth of block nesting. */ + int block_depth; + /* List of pending variable definitions. */ + struct stab_pending_var *pending; + /* Number of files for which we have types. */ + unsigned int files; + /* Lists of types per file. */ + struct stab_types **file_types; + /* Predefined XCOFF types. */ + debug_type xcoff_types[XCOFF_TYPE_COUNT]; + /* Undefined tags. */ + struct stab_tag *tags; +}; + +/* A list of these structures is used to hold pending variable + definitions seen before the N_LBRAC of a block. */ + +struct stab_pending_var +{ + /* Next pending variable definition. */ + struct stab_pending_var *next; + /* Name. */ + const char *name; + /* Type. */ + debug_type type; + /* Kind. */ + enum debug_var_kind kind; + /* Value. */ + bfd_vma val; +}; + +/* A list of these structures is used to hold the types for a single + file. */ + +struct stab_types +{ + /* Next set of slots for this file. */ + struct stab_types *next; + /* Types indexed by type number. */ +#define STAB_TYPES_SLOTS (16) + debug_type types[STAB_TYPES_SLOTS]; +}; + +/* We keep a list of undefined tags that we encounter, so that we can + fill them in if the tag is later defined. */ + +struct stab_tag +{ + /* Next undefined tag. */ + struct stab_tag *next; + /* Tag name. */ + const char *name; + /* Type kind. */ + enum debug_type_kind kind; + /* Slot to hold real type when we discover it. If we don't, we fill + in an undefined tag type. */ + debug_type slot; + /* Indirect type we have created to point at slot. */ + debug_type type; +}; + +static char *savestring PARAMS ((const char *, int)); +static bfd_vma parse_number PARAMS ((const char **, boolean *)); +static void bad_stab PARAMS ((const char *)); +static void warn_stab PARAMS ((const char *, const char *)); +static boolean parse_stab_string + PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *)); +static debug_type parse_stab_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + debug_type **)); +static boolean parse_stab_type_number + PARAMS ((const char **, int *)); +static debug_type parse_stab_range_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *)); +static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **)); +static debug_type parse_stab_sun_floating_type + PARAMS ((PTR, const char **)); +static debug_type parse_stab_enum_type PARAMS ((PTR, const char **)); +static debug_type parse_stab_struct_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean, + const int *)); +static boolean parse_stab_baseclasses + PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **)); +static boolean parse_stab_struct_fields + PARAMS ((PTR, struct stab_handle *, const char **, debug_field **, + boolean *)); +static boolean parse_stab_cpp_abbrev + PARAMS ((PTR, struct stab_handle *, const char **, debug_field *)); +static boolean parse_stab_one_struct_field + PARAMS ((PTR, struct stab_handle *, const char **, const char *, + debug_field *, boolean *)); +static boolean parse_stab_members + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *, debug_method **)); +static debug_type parse_stab_argtypes + PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *, + debug_type, const char *, boolean, boolean, const char **)); +static boolean parse_stab_tilde_field + PARAMS ((PTR, struct stab_handle *, const char **, const int *, + debug_type *, boolean *)); +static debug_type parse_stab_array_type + PARAMS ((PTR, struct stab_handle *, const char **, boolean)); +static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma)); +static const char *pop_bincl PARAMS ((struct stab_handle *)); +static boolean find_excl + PARAMS ((struct stab_handle *, const char *, bfd_vma)); +static boolean stab_record_variable + PARAMS ((PTR, struct stab_handle *, const char *, debug_type, + enum debug_var_kind, bfd_vma)); +static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *)); +static debug_type *stab_find_slot + PARAMS ((struct stab_handle *, const int *)); +static debug_type stab_find_type + PARAMS ((PTR, struct stab_handle *, const int *)); +static boolean stab_record_type + PARAMS ((PTR, struct stab_handle *, const int *, debug_type)); +static debug_type stab_xcoff_builtin_type + PARAMS ((PTR, struct stab_handle *, int)); +static debug_type stab_find_tagged_type + PARAMS ((PTR, struct stab_handle *, const char *, int, + enum debug_type_kind)); +static debug_type *stab_demangle_argtypes + PARAMS ((PTR, struct stab_handle *, const char *, boolean *)); + +/* Save a string in memory. */ + +static char * +savestring (start, len) + const char *start; + int len; +{ + char *ret; + + ret = (char *) xmalloc (len + 1); + memcpy (ret, start, len); + ret[len] = '\0'; + return ret; +} + +/* Read a number from a string. */ + +static bfd_vma +parse_number (pp, poverflow) + const char **pp; + boolean *poverflow; +{ + unsigned long ul; + const char *orig; + + if (poverflow != NULL) + *poverflow = false; + + orig = *pp; + + errno = 0; + ul = strtoul (*pp, (char **) pp, 0); + if (ul + 1 != 0 || errno == 0) + return (bfd_vma) ul; + + /* Note that even though strtoul overflowed, it should have set *pp + to the end of the number, which is where we want it. */ + + if (sizeof (bfd_vma) > sizeof (unsigned long)) + { + const char *p; + boolean neg; + int base; + bfd_vma over, lastdig; + boolean overflow; + bfd_vma v; + + /* Our own version of strtoul, for a bfd_vma. */ + + p = orig; + + neg = false; + if (*p == '+') + ++p; + else if (*p == '-') + { + neg = true; + ++p; + } + + base = 10; + if (*p == '0') + { + if (p[1] == 'x' || p[1] == 'X') + { + base = 16; + p += 2; + } + else + { + base = 8; + ++p; + } + } + + over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base; + lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base; + + overflow = false; + v = 0; + while (1) + { + int d; + + d = *p++; + if (isdigit ((unsigned char) d)) + d -= '0'; + else if (isupper ((unsigned char) d)) + d -= 'A'; + else if (islower ((unsigned char) d)) + d -= 'a'; + else + break; + + if (d >= base) + break; + + if (v > over || (v == over && (bfd_vma) d > lastdig)) + { + overflow = true; + break; + } + } + + if (! overflow) + { + if (neg) + v = - v; + return v; + } + } + + /* If we get here, the number is too large to represent in a + bfd_vma. */ + + if (poverflow != NULL) + *poverflow = true; + else + warn_stab (orig, "numeric overflow"); + + return 0; +} + +/* Give an error for a bad stab string. */ + +static void +bad_stab (p) + const char *p; +{ + fprintf (stderr, "Bad stab: %s\n", p); +} + +/* Warn about something in a stab string. */ + +static void +warn_stab (p, err) + const char *p; + const char *err; +{ + fprintf (stderr, "Warning: %s: %s\n", err, p); +} + +/* Create a handle to parse stabs symbols with. */ + +/*ARGSUSED*/ +PTR +start_stab (dhandle, abfd, sections, syms, symcount) + PTR dhandle; + bfd *abfd; + boolean sections; + asymbol **syms; + long symcount; +{ + struct stab_handle *ret; + + ret = (struct stab_handle *) xmalloc (sizeof *ret); + memset (ret, 0, sizeof *ret); + ret->abfd = abfd; + ret->sections = sections; + ret->syms = syms; + ret->symcount = symcount; + ret->files = 1; + ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types); + ret->file_types[0] = NULL; + ret->function_end = (bfd_vma) -1; + return (PTR) ret; +} + +/* When we have processed all the stabs information, we need to go + through and fill in all the undefined tags. */ + +boolean +finish_stab (dhandle, handle) + PTR dhandle; + PTR handle; +{ + struct stab_handle *info = (struct stab_handle *) handle; + struct stab_tag *st; + + if (info->within_function) + { + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, info->function_end)) + return false; + info->within_function = false; + info->function_end = (bfd_vma) -1; + } + + for (st = info->tags; st != NULL; st = st->next) + { + enum debug_type_kind kind; + + kind = st->kind; + if (kind == DEBUG_KIND_ILLEGAL) + kind = DEBUG_KIND_STRUCT; + st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind); + if (st->slot == DEBUG_TYPE_NULL) + return false; + } + + return true; +} + +/* Handle a single stabs symbol. */ + +boolean +parse_stab (dhandle, handle, type, desc, value, string) + PTR dhandle; + PTR handle; + int type; + int desc; + bfd_vma value; + const char *string; +{ + struct stab_handle *info = (struct stab_handle *) handle; + + /* gcc will emit two N_SO strings per compilation unit, one for the + directory name and one for the file name. We just collect N_SO + strings as we see them, and start the new compilation unit when + we see a non N_SO symbol. */ + if (info->so_string != NULL + && (type != N_SO || *string == '\0' || value != info->so_value)) + { + if (! debug_set_filename (dhandle, info->so_string)) + return false; + info->main_filename = info->so_string; + + info->gcc_compiled = 0; + info->n_opt_found = false; + + /* Generally, for stabs in the symbol table, the N_LBRAC and + N_RBRAC symbols are relative to the N_SO symbol value. */ + if (! info->sections) + info->file_start_offset = info->so_value; + + /* We need to reset the mapping from type numbers to types. We + can't free the old mapping, because of the use of + debug_make_indirect_type. */ + info->files = 1; + info->file_types = ((struct stab_types **) + xmalloc (sizeof *info->file_types)); + info->file_types[0] = NULL; + + info->so_string = NULL; + + /* Now process whatever type we just got. */ + } + + switch (type) + { + case N_FN: + case N_FN_SEQ: + break; + + case N_LBRAC: + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (info->n_opt_found && desc == 1) + break; + + if (! info->within_function) + { + fprintf (stderr, "N_LBRAC not within function\n"); + return false; + } + + /* Start an inner lexical block. */ + if (! debug_start_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) + return false; + + /* Emit any pending variable definitions. */ + if (! stab_emit_pending_vars (dhandle, info)) + return false; + + ++info->block_depth; + break; + + case N_RBRAC: + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (info->n_opt_found && desc == 1) + break; + + /* We shouldn't have any pending variable definitions here, but, + if we do, we probably need to emit them before closing the + block. */ + if (! stab_emit_pending_vars (dhandle, info)) + return false; + + /* End an inner lexical block. */ + if (! debug_end_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) + return false; + + --info->block_depth; + if (info->block_depth < 0) + { + fprintf (stderr, "Too many N_RBRACs\n"); + return false; + } + break; + + case N_SO: + /* This always ends a function. */ + if (info->within_function) + { + bfd_vma endval; + + endval = value; + if (*string != '\0' + && info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) + return false; + info->within_function = false; + info->function_end = (bfd_vma) -1; + } + + /* An empty string is emitted by gcc at the end of a compilation + unit. */ + if (*string == '\0') + return true; + + /* Just accumulate strings until we see a non N_SO symbol. If + the string starts with '/', we discard the previously + accumulated strings. */ + if (info->so_string == NULL) + info->so_string = xstrdup (string); + else + { + char *f; + + f = info->so_string; + if (*string == '/') + info->so_string = xstrdup (string); + else + info->so_string = concat (info->so_string, string, + (const char *) NULL); + free (f); + } + + info->so_value = value; + + break; + + case N_SOL: + /* Start an include file. */ + if (! debug_start_source (dhandle, string)) + return false; + break; + + case N_BINCL: + /* Start an include file which may be replaced. */ + push_bincl (info, string, value); + if (! debug_start_source (dhandle, string)) + return false; + break; + + case N_EINCL: + /* End an N_BINCL include. */ + if (! debug_start_source (dhandle, pop_bincl (info))) + return false; + break; + + case N_EXCL: + /* This is a duplicate of a header file named by N_BINCL which + was eliminated by the linker. */ + if (! find_excl (info, string, value)) + return false; + break; + + case N_SLINE: + if (! debug_record_line (dhandle, desc, + value + info->function_start_offset)) + return false; + break; + + case N_BCOMM: + if (! debug_start_common_block (dhandle, string)) + return false; + break; + + case N_ECOMM: + if (! debug_end_common_block (dhandle, string)) + return false; + break; + + case N_FUN: + if (*string == '\0') + { + if (info->within_function) + { + /* This always marks the end of a function; we don't + need to worry about info->function_end. */ + if (info->sections) + value += info->function_start_offset; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, value)) + return false; + info->within_function = false; + info->function_end = (bfd_vma) -1; + } + break; + } + + /* A const static symbol in the .text section will have an N_FUN + entry. We need to use these to mark the end of the function, + in case we are looking at gcc output before it was changed to + always emit an empty N_FUN. We can't call debug_end_function + here, because it might be a local static symbol. */ + if (info->within_function + && (info->function_end == (bfd_vma) -1 + || value < info->function_end)) + info->function_end = value; + + /* Fall through. */ + /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM + symbols, and if it does not start with :S, gdb relocates the + value to the start of the section. gcc always seems to use + :S, so we don't worry about this. */ + /* Fall through. */ + default: + { + const char *colon; + + colon = strchr (string, ':'); + if (colon != NULL + && (colon[1] == 'f' || colon[1] == 'F')) + { + if (info->within_function) + { + bfd_vma endval; + + endval = value; + if (info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) + return false; + info->function_end = (bfd_vma) -1; + } + /* For stabs in sections, line numbers and block addresses + are offsets from the start of the function. */ + if (info->sections) + info->function_start_offset = value; + info->within_function = true; + } + + if (! parse_stab_string (dhandle, info, type, desc, value, string)) + return false; + } + break; + + case N_OPT: + if (string != NULL && strcmp (string, "gcc2_compiled.") == 0) + info->gcc_compiled = 2; + else if (string != NULL && strcmp (string, "gcc_compiled.") == 0) + info->gcc_compiled = 1; + else + info->n_opt_found = true; + break; + + case N_OBJ: + case N_ENDM: + case N_MAIN: + break; + } + + return true; +} + +/* Parse the stabs string. */ + +static boolean +parse_stab_string (dhandle, info, stabtype, desc, value, string) + PTR dhandle; + struct stab_handle *info; + int stabtype; + int desc; + bfd_vma value; + const char *string; +{ + const char *p; + char *name; + int type; + debug_type dtype; + boolean synonym; + unsigned int lineno; + debug_type *slot; + + p = strchr (string, ':'); + if (p == NULL) + return true; + + while (p[1] == ':') + { + p += 2; + p = strchr (p, ':'); + if (p == NULL) + { + bad_stab (string); + return false; + } + } + + /* GCC 2.x puts the line number in desc. SunOS apparently puts in + the number of bytes occupied by a type or object, which we + ignore. */ + if (info->gcc_compiled >= 2) + lineno = desc; + else + lineno = 0; + + /* FIXME: Sometimes the special C++ names start with '.'. */ + name = NULL; + if (string[0] == '$') + { + switch (string[1]) + { + case 't': + name = "this"; + break; + case 'v': + /* Was: name = "vptr"; */ + break; + case 'e': + name = "eh_throw"; + break; + case '_': + /* This was an anonymous type that was never fixed up. */ + break; + case 'X': + /* SunPRO (3.0 at least) static variable encoding. */ + break; + default: + warn_stab (string, "unknown C++ encoded name"); + break; + } + } + + if (name == NULL) + { + if (p == string || (string[0] == ' ' && p == string + 1)) + name = NULL; + else + name = savestring (string, p - string); + } + + ++p; + if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-') + type = 'l'; + else + type = *p++; + + switch (type) + { + case 'c': + /* c is a special case, not followed by a type-number. + SYMBOL:c=iVALUE for an integer constant symbol. + SYMBOL:c=rVALUE for a floating constant symbol. + SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + if (*p != '=') + { + bad_stab (string); + return false; + } + ++p; + switch (*p++) + { + case 'r': + /* Floating point constant. */ + if (! debug_record_float_const (dhandle, name, atof (p))) + return false; + break; + case 'i': + /* Integer constant. */ + /* Defining integer constants this way is kind of silly, + since 'e' constants allows the compiler to give not only + the value, but the type as well. C has at least int, + long, unsigned int, and long long as constant types; + other languages probably should have at least unsigned as + well as signed constants. */ + if (! debug_record_int_const (dhandle, name, atoi (p))) + return false; + break; + case 'e': + /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value + can be represented as integral. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (*p != ',') + { + bad_stab (string); + return false; + } + if (! debug_record_typed_const (dhandle, name, dtype, atoi (p))) + return false; + break; + default: + bad_stab (string); + return false; + } + + break; + + case 'C': + /* The name of a caught exception. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_label (dhandle, name, dtype, value)) + return false; + break; + + case 'f': + case 'F': + /* A function definition. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_function (dhandle, name, dtype, type == 'F', value)) + return false; + + /* Sun acc puts declared types of arguments here. We don't care + about their actual types (FIXME -- we should remember the whole + function prototype), but the list may define some new types + that we have to remember, so we must scan it now. */ + while (*p == ';') + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) + == DEBUG_TYPE_NULL) + return false; + } + + break; + + case 'G': + { + char leading; + long c; + asymbol **ps; + + /* A global symbol. The value must be extracted from the + symbol table. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + leading = bfd_get_symbol_leading_char (info->abfd); + for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps) + { + const char *n; + + n = bfd_asymbol_name (*ps); + if (leading != '\0' && *n == leading) + ++n; + if (*n == *name && strcmp (n, name) == 0) + break; + } + if (c > 0) + value = bfd_asymbol_value (*ps); + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, + value)) + return false; + } + break; + + /* This case is faked by a conditional above, when there is no + code letter in the dbx data. Dbx data never actually + contains 'l'. */ + case 'l': + case 's': + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, + value)) + return false; + break; + + case 'p': + /* A function parameter. */ + if (*p != 'F') + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + else + { + /* pF is a two-letter code that means a function parameter in + Fortran. The type-number specifies the type of the return + value. Translate it into a pointer-to-function type. */ + ++p; + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype != DEBUG_TYPE_NULL) + { + debug_type ftype; + + ftype = debug_make_function_type (dhandle, dtype, + (debug_type *) NULL, false); + dtype = debug_make_pointer_type (dhandle, ftype); + } + } + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK, + value)) + return false; + + /* FIXME: At this point gdb considers rearranging the parameter + address on a big endian machine if it is smaller than an int. + We have no way to do that, since we don't really know much + about the target. */ + + break; + + case 'P': + if (stabtype == N_FUN) + { + /* Prototype of a function referenced by this file. */ + while (*p == ';') + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) + == DEBUG_TYPE_NULL) + return false; + } + break; + } + /* Fall through. */ + case 'R': + /* Parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG, + value)) + return false; + break; + + case 'r': + /* Register variable (either global or local). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER, + value)) + return false; + + /* FIXME: At this point gdb checks to combine pairs of 'p' and + 'r' stabs into a single 'P' stab. */ + + break; + + case 'S': + /* Static symbol at top level of file */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC, + value)) + return false; + break; + + case 't': + /* A typedef. */ + dtype = parse_stab_type (dhandle, info, name, &p, &slot); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (name == NULL) + { + /* A nameless type. Nothing to do. */ + return true; + } + + dtype = debug_name_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return false; + + if (slot != NULL) + *slot = dtype; + + break; + + case 'T': + /* Struct, union, or enum tag. For GNU C++, this can be be followed + by 't' which means we are typedef'ing it as well. */ + if (*p != 't') + { + synonym = false; + /* FIXME: gdb sets synonym to true if the current language + is C++. */ + } + else + { + synonym = true; + ++p; + } + + dtype = parse_stab_type (dhandle, info, name, &p, &slot); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (name == NULL) + return true; + + dtype = debug_tag_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (slot != NULL) + *slot = dtype; + + /* See if we have a cross reference to this tag which we can now + fill in. */ + { + register struct stab_tag **pst; + + for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next) + { + if ((*pst)->name[0] == name[0] + && strcmp ((*pst)->name, name) == 0) + { + (*pst)->slot = dtype; + *pst = (*pst)->next; + break; + } + } + } + + if (synonym) + { + dtype = debug_name_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return false; + + if (slot != NULL) + *slot = dtype; + } + + break; + + case 'V': + /* Static symbol of local scope */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + /* FIXME: gdb checks os9k_stabs here. */ + if (! stab_record_variable (dhandle, info, name, dtype, + DEBUG_LOCAL_STATIC, value)) + return false; + break; + + case 'v': + /* Reference parameter. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE, + value)) + return false; + break; + + case 'a': + /* Reference parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG, + value)) + return false; + break; + + case 'X': + /* This is used by Sun FORTRAN for "function result value". + Sun claims ("dbx and dbxtool interfaces", 2nd ed) + that Pascal uses it too, but when I tried it Pascal used + "x:3" (local symbol) instead. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, + value)) + return false; + break; + + default: + bad_stab (string); + return false; + } + + /* FIXME: gdb converts structure values to structure pointers in a + couple of cases, depending upon the target. */ + + return true; +} + +/* Parse a stabs type. The typename argument is non-NULL if this is a + typedef or a tag definition. The pp argument points to the stab + string, and is updated. The slotp argument points to a place to + store the slot used if the type is being defined. */ + +static debug_type +parse_stab_type (dhandle, info, typename, pp, slotp) + PTR dhandle; + struct stab_handle *info; + const char *typename; + const char **pp; + debug_type **slotp; +{ + const char *orig; + int typenums[2]; + int size; + boolean stringp; + int descriptor; + debug_type dtype; + + if (slotp != NULL) + *slotp = NULL; + + orig = *pp; + + size = -1; + stringp = false; + + /* Read type number if present. The type number may be omitted. + for instance in a two-dimensional array declared with type + "ar1;1;10;ar1;1;10;4". */ + if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-') + { + /* 'typenums=' not present, type is anonymous. Read and return + the definition, but don't put it in the type vector. */ + typenums[0] = typenums[1] = -1; + } + else + { + if (! parse_stab_type_number (pp, typenums)) + return DEBUG_TYPE_NULL; + + if (**pp != '=') + { + /* Type is not being defined here. Either it already + exists, or this is a forward reference to it. */ + return stab_find_type (dhandle, info, typenums); + } + + /* Only set the slot if the type is being defined. This means + that the mapping from type numbers to types will only record + the name of the typedef which defines a type. If we don't do + this, then something like + typedef int foo; + int i; + will record that i is of type foo. Unfortunately, stabs + information is ambiguous about variable types. For this code, + typedef int foo; + int i; + foo j; + the stabs information records both i and j as having the same + type. This could be fixed by patching the compiler. */ + if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0) + *slotp = stab_find_slot (info, typenums); + + /* Type is being defined here. */ + /* Skip the '='. */ + ++*pp; + + while (**pp == '@') + { + const char *p = *pp + 1; + const char *attr; + + if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-') + { + /* Member type. */ + break; + } + + /* Type attributes. */ + attr = p; + + for (; *p != ';'; ++p) + { + if (*p == '\0') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + } + *pp = p + 1; + + switch (*attr) + { + case 's': + size = atoi (attr + 1); + if (size <= 0) + size = -1; + break; + + case 'S': + stringp = true; + break; + + default: + /* Ignore unrecognized type attributes, so future + compilers can invent new ones. */ + break; + } + } + } + + descriptor = **pp; + ++*pp; + + switch (descriptor) + { + case 'x': + { + enum debug_type_kind code; + const char *q1, *q2, *p; + + /* A cross reference to another type. */ + + switch (**pp) + { + case 's': + code = DEBUG_KIND_STRUCT; + break; + case 'u': + code = DEBUG_KIND_UNION; + break; + case 'e': + code = DEBUG_KIND_ENUM; + break; + default: + /* Complain and keep going, so compilers can invent new + cross-reference types. */ + warn_stab (orig, "unrecognized cross reference type"); + code = DEBUG_KIND_STRUCT; + break; + } + ++*pp; + + q1 = strchr (*pp, '<'); + p = strchr (*pp, ':'); + if (p == NULL) + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + while (q1 != NULL && p > q1 && p[1] == ':') + { + q2 = strchr (q1, '>'); + if (q2 == NULL || q2 < p) + break; + p += 2; + p = strchr (p, ':'); + if (p == NULL) + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + } + + dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code); + + *pp = p + 1; + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '(': + { + const char *hold; + int xtypenums[2]; + + /* This type is defined as another type. */ + + (*pp)--; + hold = *pp; + + /* Peek ahead at the number to detect void. */ + if (! parse_stab_type_number (pp, xtypenums)) + return DEBUG_TYPE_NULL; + + if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) + { + /* This type is being defined as itself, which means that + it is void. */ + dtype = debug_make_void_type (dhandle); + } + else + { + *pp = hold; + + /* Go back to the number and have parse_stab_type get it. + This means that we can deal with something like + t(1,2)=(3,4)=... which the Lucid compiler uses. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + + if (typenums[0] != -1) + { + if (! stab_record_type (dhandle, info, typenums, dtype)) + return DEBUG_TYPE_NULL; + } + + break; + } + + case '*': + dtype = debug_make_pointer_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL)); + break; + + case '&': + /* Reference to another type. */ + dtype = (debug_make_reference_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); + break; + + case 'f': + /* Function returning another type. */ + /* FIXME: gdb checks os9k_stabs here. */ + dtype = (debug_make_function_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL), + (debug_type *) NULL, false)); + break; + + case 'k': + /* Const qualifier on some type (Sun). */ + /* FIXME: gdb accepts 'c' here if os9k_stabs. */ + dtype = debug_make_const_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL)); + break; + + case 'B': + /* Volatile qual on some type (Sun). */ + /* FIXME: gdb accepts 'i' here if os9k_stabs. */ + dtype = (debug_make_volatile_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); + break; + + case '@': + /* Offset (class & variable) type. This is used for a pointer + relative to an object. */ + { + debug_type domain; + debug_type memtype; + + /* Member type. */ + + domain = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (memtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + dtype = debug_make_offset_type (dhandle, domain, memtype); + } + break; + + case '#': + /* Method (class & fn) type. */ + if (**pp == '#') + { + debug_type return_type; + + ++*pp; + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + dtype = debug_make_method_type (dhandle, return_type, + DEBUG_TYPE_NULL, + (debug_type *) NULL, false); + } + else + { + debug_type domain; + debug_type return_type; + debug_type *args; + unsigned int n; + unsigned int alloc; + boolean varargs; + + domain = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + alloc = 10; + args = (debug_type *) xmalloc (alloc * sizeof *args); + n = 0; + while (**pp != ';') + { + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (n + 1 >= alloc) + { + alloc += 10; + args = ((debug_type *) + xrealloc ((PTR) args, alloc * sizeof *args)); + } + + args[n] = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (args[n] == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + ++n; + } + ++*pp; + + /* If the last type is not void, then this function takes a + variable number of arguments. Otherwise, we must strip + the void type. */ + if (n == 0 + || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID) + varargs = true; + else + { + --n; + varargs = false; + } + + args[n] = DEBUG_TYPE_NULL; + + dtype = debug_make_method_type (dhandle, return_type, domain, args, + varargs); + } + break; + + case 'r': + /* Range type. */ + dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums); + break; + + case 'b': + /* FIXME: gdb checks os9k_stabs here. */ + /* Sun ACC builtin int type. */ + dtype = parse_stab_sun_builtin_type (dhandle, pp); + break; + + case 'R': + /* Sun ACC builtin float type. */ + dtype = parse_stab_sun_floating_type (dhandle, pp); + break; + + case 'e': + /* Enumeration type. */ + dtype = parse_stab_enum_type (dhandle, pp); + break; + + case 's': + case 'u': + /* Struct or union type. */ + dtype = parse_stab_struct_type (dhandle, info, typename, pp, + descriptor == 's', typenums); + break; + + case 'a': + /* Array type. */ + if (**pp != 'r') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + dtype = parse_stab_array_type (dhandle, info, pp, stringp); + break; + + case 'S': + dtype = debug_make_set_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL), + stringp); + break; + + default: + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + if (dtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (typenums[0] != -1) + { + if (! stab_record_type (dhandle, info, typenums, dtype)) + return DEBUG_TYPE_NULL; + } + + if (size != -1) + { + if (! debug_record_type_size (dhandle, dtype, (unsigned int) size)) + return DEBUG_TYPE_NULL; + } + + return dtype; +} + +/* Read a number by which a type is referred to in dbx data, or + perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a + single number N is equivalent to (0,N). Return the two numbers by + storing them in the vector TYPENUMS. */ + +static boolean +parse_stab_type_number (pp, typenums) + const char **pp; + int *typenums; +{ + const char *orig; + + orig = *pp; + + if (**pp != '(') + { + typenums[0] = 0; + typenums[1] = (int) parse_number (pp, (boolean *) NULL); + } + else + { + ++*pp; + typenums[0] = (int) parse_number (pp, (boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + typenums[1] = (int) parse_number (pp, (boolean *) NULL); + if (**pp != ')') + { + bad_stab (orig); + return false; + } + ++*pp; + } + + return true; +} + +/* Parse a range type. */ + +static debug_type +parse_stab_range_type (dhandle, info, typename, pp, typenums) + PTR dhandle; + struct stab_handle *info; + const char *typename; + const char **pp; + const int *typenums; +{ + const char *orig; + int rangenums[2]; + boolean self_subrange; + debug_type index_type; + const char *s2, *s3; + bfd_signed_vma n2, n3; + boolean ov2, ov3; + + orig = *pp; + + index_type = DEBUG_TYPE_NULL; + + /* First comes a type we are a subrange of. + In C it is usually 0, 1 or the type being defined. */ + if (! parse_stab_type_number (pp, rangenums)) + return DEBUG_TYPE_NULL; + + self_subrange = (rangenums[0] == typenums[0] + && rangenums[1] == typenums[1]); + + if (**pp == '=') + { + *pp = orig; + index_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (index_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + + if (**pp == ';') + ++*pp; + + /* The remaining two operands are usually lower and upper bounds of + the range. But in some special cases they mean something else. */ + s2 = *pp; + n2 = parse_number (pp, &ov2); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + s3 = *pp; + n3 = parse_number (pp, &ov3); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (ov2 || ov3) + { + /* gcc will emit range stabs for long long types. Handle this + as a special case. FIXME: This needs to be more general. */ +#define LLLOW "01000000000000000000000;" +#define LLHIGH "0777777777777777777777;" +#define ULLHIGH "01777777777777777777777;" + if (index_type == DEBUG_TYPE_NULL) + { + if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0 + && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0) + return debug_make_int_type (dhandle, 8, false); + if (! ov2 + && n2 == 0 + && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0) + return debug_make_int_type (dhandle, 8, true); + } + + warn_stab (orig, "numeric overflow"); + } + + if (index_type == DEBUG_TYPE_NULL) + { + /* A type defined as a subrange of itself, with both bounds 0, + is void. */ + if (self_subrange && n2 == 0 && n3 == 0) + return debug_make_void_type (dhandle); + + /* A type defined as a subrange of itself, with n2 positive and + n3 zero, is a complex type, and n2 is the number of bytes. */ + if (self_subrange && n3 == 0 && n2 > 0) + return debug_make_complex_type (dhandle, n2); + + /* If n3 is zero and n2 is positive, this is a floating point + type, and n2 is the number of bytes. */ + if (n3 == 0 && n2 > 0) + return debug_make_float_type (dhandle, n2); + + /* If the upper bound is -1, this is an unsigned int. */ + if (n2 == 0 && n3 == -1) + { + /* When gcc is used with -gstabs, but not -gstabs+, it will emit + long long int:t6=r1;0;-1; + long long unsigned int:t7=r1;0;-1; + We hack here to handle this reasonably. */ + if (typename != NULL) + { + if (strcmp (typename, "long long int") == 0) + return debug_make_int_type (dhandle, 8, false); + else if (strcmp (typename, "long long unsigned int") == 0) + return debug_make_int_type (dhandle, 8, true); + } + /* FIXME: The size here really depends upon the target. */ + return debug_make_int_type (dhandle, 4, true); + } + + /* A range of 0 to 127 is char. */ + if (self_subrange && n2 == 0 && n3 == 127) + return debug_make_int_type (dhandle, 1, false); + + /* FIXME: gdb checks for the language CHILL here. */ + + if (n2 == 0) + { + if (n3 < 0) + return debug_make_int_type (dhandle, - n3, true); + else if (n3 == 0xff) + return debug_make_int_type (dhandle, 1, true); + else if (n3 == 0xffff) + return debug_make_int_type (dhandle, 2, true); + /* -1 is used for the upper bound of (4 byte) "unsigned int" + and "unsigned long", and we already checked for that, so + don't need to test for it here. */ + } + else if (n3 == 0 + && n2 < 0 + && (self_subrange || n2 == -8)) + return debug_make_int_type (dhandle, - n2, true); + else if (n2 == - n3 - 1) + { + if (n3 == 0x7f) + return debug_make_int_type (dhandle, 1, false); + else if (n3 == 0x7fff) + return debug_make_int_type (dhandle, 2, false); + else if (n3 == 0x7fffffff) + return debug_make_int_type (dhandle, 4, false); + } + } + + /* At this point I don't have the faintest idea how to deal with a + self_subrange type; I'm going to assume that this is used as an + idiom, and that all of them are special cases. So . . . */ + if (self_subrange) + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + index_type = stab_find_type (dhandle, info, rangenums); + if (index_type == DEBUG_TYPE_NULL) + { + /* Does this actually ever happen? Is that why we are worrying + about dealing with it rather than just calling error_type? */ + warn_stab (orig, "missing index type"); + index_type = debug_make_int_type (dhandle, 4, false); + } + + return debug_make_range_type (dhandle, index_type, n2, n3); +} + +/* Sun's ACC uses a somewhat saner method for specifying the builtin + typedefs in every file (for int, long, etc): + + type = b <signed> <width>; <offset>; <nbits> + signed = u or s. Possible c in addition to u or s (for char?). + offset = offset from high order bit to start bit of type. + width is # bytes in object of this type, nbits is # bits in type. + + The width/offset stuff appears to be for small objects stored in + larger ones (e.g. `shorts' in `int' registers). We ignore it for now, + FIXME. */ + +static debug_type +parse_stab_sun_builtin_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + boolean unsignedp; + bfd_vma bits; + + orig = *pp; + + switch (**pp) + { + case 's': + unsignedp = false; + break; + case 'u': + unsignedp = true; + break; + default: + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* For some odd reason, all forms of char put a c here. This is strange + because no other type has this honor. We can safely ignore this because + we actually determine 'char'acterness by the number of bits specified in + the descriptor. */ + if (**pp == 'c') + ++*pp; + + /* The first number appears to be the number of bytes occupied + by this type, except that unsigned short is 4 instead of 2. + Since this information is redundant with the third number, + we will ignore it. */ + (void) parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* The second number is always 0, so ignore it too. */ + (void) parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* The third number is the number of bits for this type. */ + bits = parse_number (pp, (boolean *) NULL); + + /* The type *should* end with a semicolon. If it are embedded + in a larger type the semicolon may be the only way to know where + the type ends. If this type is at the end of the stabstring we + can deal with the omitted semicolon (but we don't have to like + it). Don't bother to complain(), Sun's compiler omits the semicolon + for "void". */ + if (**pp == ';') + ++*pp; + + if (bits == 0) + return debug_make_void_type (dhandle); + + return debug_make_int_type (dhandle, bits / 8, unsignedp); +} + +/* Parse a builtin floating type generated by the Sun compiler. */ + +static debug_type +parse_stab_sun_floating_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + bfd_vma details; + bfd_vma bytes; + + orig = *pp; + + /* The first number has more details about the type, for example + FN_COMPLEX. */ + details = parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + /* The second number is the number of bytes occupied by this type */ + bytes = parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + if (details == NF_COMPLEX + || details == NF_COMPLEX16 + || details == NF_COMPLEX32) + return debug_make_complex_type (dhandle, bytes); + + return debug_make_float_type (dhandle, bytes); +} + +/* Handle an enum type. */ + +static debug_type +parse_stab_enum_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + const char **names; + bfd_signed_vma *values; + unsigned int n; + unsigned int alloc; + + orig = *pp; + + /* FIXME: gdb checks os9k_stabs here. */ + + /* The aix4 compiler emits an extra field before the enum members; + my guess is it's a type of some sort. Just ignore it. */ + if (**pp == '-') + { + while (**pp != ':') + ++*pp; + ++*pp; + } + + /* Read the value-names and their values. + The input syntax is NAME:VALUE,NAME:VALUE, and so on. + A semicolon or comma instead of a NAME means the end. */ + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values); + n = 0; + while (**pp != '\0' && **pp != ';' && **pp != ',') + { + const char *p; + char *name; + bfd_signed_vma val; + + p = *pp; + while (*p != ':') + ++p; + + name = savestring (*pp, p - *pp); + + *pp = p + 1; + val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (n + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc ((PTR) names, alloc * sizeof *names)); + values = ((bfd_signed_vma *) + xrealloc ((PTR) values, alloc * sizeof *values)); + } + + names[n] = name; + values[n] = val; + ++n; + } + + names[n] = NULL; + values[n] = 0; + + if (**pp == ';') + ++*pp; + + return debug_make_enum_type (dhandle, names, values); +} + +/* Read the description of a structure (or union type) and return an object + describing the type. + + PP points to a character pointer that points to the next unconsumed token + in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;", + *PP will point to "4a:1,0,32;;". */ + +static debug_type +parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums) + PTR dhandle; + struct stab_handle *info; + const char *tagname; + const char **pp; + boolean structp; + const int *typenums; +{ + const char *orig; + bfd_vma size; + debug_baseclass *baseclasses; + debug_field *fields; + boolean statics; + debug_method *methods; + debug_type vptrbase; + boolean ownvptr; + + orig = *pp; + + /* Get the size. */ + size = parse_number (pp, (boolean *) NULL); + + /* Get the other information. */ + if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses) + || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics) + || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods) + || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase, + &ownvptr)) + return DEBUG_TYPE_NULL; + + if (! statics + && baseclasses == NULL + && methods == NULL + && vptrbase == DEBUG_TYPE_NULL + && ! ownvptr) + return debug_make_struct_type (dhandle, structp, size, fields); + + return debug_make_object_type (dhandle, structp, size, fields, baseclasses, + methods, vptrbase, ownvptr); +} + +/* The stabs for C++ derived classes contain baseclass information which + is marked by a '!' character after the total size. This function is + called when we encounter the baseclass marker, and slurps up all the + baseclass information. + + Immediately following the '!' marker is the number of base classes that + the class is derived from, followed by information for each base class. + For each base class, there are two visibility specifiers, a bit offset + to the base class information within the derived class, a reference to + the type for the base class, and a terminating semicolon. + + A typical example, with two base classes, would be "!2,020,19;0264,21;". + ^^ ^ ^ ^ ^ ^ ^ + Baseclass information marker __________________|| | | | | | | + Number of baseclasses __________________________| | | | | | | + Visibility specifiers (2) ________________________| | | | | | + Offset in bits from start of class _________________| | | | | + Type number for base class ___________________________| | | | + Visibility specifiers (2) _______________________________| | | + Offset in bits from start of class ________________________| | + Type number of base class ____________________________________| + + Return true for success, false for failure. */ + +static boolean +parse_stab_baseclasses (dhandle, info, pp, retp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_baseclass **retp; +{ + const char *orig; + unsigned int c, i; + debug_baseclass *classes; + + *retp = NULL; + + orig = *pp; + + if (**pp != '!') + { + /* No base classes. */ + return true; + } + ++*pp; + + c = (unsigned int) parse_number (pp, (boolean *) NULL); + + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + + classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp)); + + for (i = 0; i < c; i++) + { + boolean virtual; + enum debug_visibility visibility; + bfd_vma bitpos; + debug_type type; + + switch (**pp) + { + case '0': + virtual = false; + break; + case '1': + virtual = true; + break; + default: + warn_stab (orig, "unknown virtual character for baseclass"); + virtual = false; + break; + } + ++*pp; + + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + default: + warn_stab (orig, "unknown visibility character for baseclass"); + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + + /* The remaining value is the bit offset of the portion of the + object corresponding to this baseclass. Always zero in the + absence of multiple inheritance. */ + bitpos = parse_number (pp, (boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return false; + + classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual, + visibility); + if (classes[i] == DEBUG_BASECLASS_NULL) + return false; + + if (**pp != ';') + return false; + ++*pp; + } + + classes[i] = DEBUG_BASECLASS_NULL; + + *retp = classes; + + return true; +} + +/* Read struct or class data fields. They have the form: + + NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ; + + At the end, we see a semicolon instead of a field. + + In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for + a static field. + + The optional VISIBILITY is one of: + + '/0' (VISIBILITY_PRIVATE) + '/1' (VISIBILITY_PROTECTED) + '/2' (VISIBILITY_PUBLIC) + '/9' (VISIBILITY_IGNORE) + + or nothing, for C style fields with public visibility. + + Returns 1 for success, 0 for failure. */ + +static boolean +parse_stab_struct_fields (dhandle, info, pp, retp, staticsp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_field **retp; + boolean *staticsp; +{ + const char *orig; + const char *p; + debug_field *fields; + unsigned int c; + unsigned int alloc; + + *retp = NULL; + *staticsp = false; + + orig = *pp; + + c = 0; + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + while (**pp != ';') + { + /* FIXME: gdb checks os9k_stabs here. */ + + p = *pp; + + /* Add 1 to c to leave room for NULL pointer at end. */ + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc ((PTR) fields, alloc * sizeof *fields)); + } + + /* If it starts with CPLUS_MARKER it is a special abbreviation, + unless the CPLUS_MARKER is followed by an underscore, in + which case it is just the name of an anonymous type, which we + should handle like any other type name. We accept either '$' + or '.', because a field name can never contain one of these + characters except as a CPLUS_MARKER. */ + + if ((*p == '$' || *p == '.') && p[1] != '_') + { + ++*pp; + if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c)) + return false; + ++c; + continue; + } + + /* Look for the ':' that separates the field name from the field + values. Data members are delimited by a single ':', while member + functions are delimited by a pair of ':'s. When we hit the member + functions (if any), terminate scan loop and return. */ + + p = strchr (p, ':'); + if (p == NULL) + { + bad_stab (orig); + return false; + } + + if (p[1] == ':') + break; + + if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c, + staticsp)) + return false; + + ++c; + } + + fields[c] = DEBUG_FIELD_NULL; + + *retp = fields; + + return true; +} + +/* Special GNU C++ name. */ + +static boolean +parse_stab_cpp_abbrev (dhandle, info, pp, retp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_field *retp; +{ + const char *orig; + int cpp_abbrev; + debug_type context; + const char *name; + const char *typename; + debug_type type; + bfd_vma bitpos; + + *retp = DEBUG_FIELD_NULL; + + orig = *pp; + + if (**pp != 'v') + { + bad_stab (*pp); + return false; + } + ++*pp; + + cpp_abbrev = **pp; + ++*pp; + + /* At this point, *pp points to something like "22:23=*22...", where + the type number before the ':' is the "context" and everything + after is a regular type definition. Lookup the type, find it's + name, and construct the field name. */ + + context = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (context == DEBUG_TYPE_NULL) + return false; + + switch (cpp_abbrev) + { + case 'f': + /* $vf -- a virtual function table pointer. */ + name = "_vptr$"; + break; + case 'b': + /* $vb -- a virtual bsomethingorother */ + typename = debug_get_type_name (dhandle, context); + if (typename == NULL) + { + warn_stab (orig, "unnamed $vb type"); + typename = "FOO"; + } + name = concat ("_vb$", typename, (const char *) NULL); + break; + default: + warn_stab (orig, "unrecognized C++ abbreviation"); + name = "INVALID_CPLUSPLUS_ABBREV"; + break; + } + + if (**pp != ':') + { + bad_stab (orig); + return false; + } + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + + bitpos = parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return false; + } + ++*pp; + + *retp = debug_make_field (dhandle, name, type, bitpos, 0, + DEBUG_VISIBILITY_PRIVATE); + if (*retp == DEBUG_FIELD_NULL) + return false; + + return true; +} + +/* Parse a single field in a struct or union. */ + +static boolean +parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + const char *p; + debug_field *retp; + boolean *staticsp; +{ + const char *orig; + char *name; + enum debug_visibility visibility; + debug_type type; + bfd_vma bitpos; + bfd_vma bitsize; + + orig = *pp; + + /* FIXME: gdb checks ARM_DEMANGLING here. */ + + name = savestring (*pp, p - *pp); + + *pp = p + 1; + + if (**pp != '/') + visibility = DEBUG_VISIBILITY_PUBLIC; + else + { + ++*pp; + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + default: + warn_stab (orig, "unknown visibility character for field"); + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + } + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return false; + + if (**pp == ':') + { + char *varname; + + /* This is a static class member. */ + ++*pp; + p = strchr (*pp, ';'); + if (p == NULL) + { + bad_stab (orig); + return false; + } + + varname = savestring (*pp, p - *pp); + + *pp = p + 1; + + *retp = debug_make_static_member (dhandle, name, type, varname, + visibility); + *staticsp = true; + + return true; + } + + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + + bitpos = parse_number (pp, (boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return false; + } + ++*pp; + + bitsize = parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return false; + } + ++*pp; + + if (bitpos == 0 && bitsize == 0) + { + /* This can happen in two cases: (1) at least for gcc 2.4.5 or + so, it is a field which has been optimized out. The correct + stab for this case is to use VISIBILITY_IGNORE, but that is a + recent invention. (2) It is a 0-size array. For example + union { int num; char str[0]; } foo. Printing "<no value>" + for str in "p foo" is OK, since foo.str (and thus foo.str[3]) + will continue to work, and a 0-size array as a whole doesn't + have any contents to print. + + I suspect this probably could also happen with gcc -gstabs + (not -gstabs+) for static fields, and perhaps other C++ + extensions. Hopefully few people use -gstabs with gdb, since + it is intended for dbx compatibility. */ + visibility = DEBUG_VISIBILITY_IGNORE; + } + + /* FIXME: gdb does some stuff here to mark fields as unpacked. */ + + *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility); + + return true; +} + +/* Read member function stabs info for C++ classes. The form of each member + function data is: + + NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ; + + An example with two member functions is: + + afunc1::20=##15;:i;2A.;afunc2::20:i;2A.; + + For the case of overloaded operators, the format is op$::*.funcs, where + $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator + name (such as `+=') and `.' marks the end of the operator name. */ + +static boolean +parse_stab_members (dhandle, info, tagname, pp, typenums, retp) + PTR dhandle; + struct stab_handle *info; + const char *tagname; + const char **pp; + const int *typenums; + debug_method **retp; +{ + const char *orig; + debug_method *methods; + unsigned int c; + unsigned int alloc; + + *retp = NULL; + + orig = *pp; + + alloc = 0; + methods = NULL; + c = 0; + + while (**pp != ';') + { + const char *p; + char *name; + debug_method_variant *variants; + unsigned int cvars; + unsigned int allocvars; + debug_type look_ahead_type; + + p = strchr (*pp, ':'); + if (p == NULL || p[1] != ':') + break; + + /* FIXME: Some systems use something other than '$' here. */ + if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$') + { + name = savestring (*pp, p - *pp); + *pp = p + 2; + } + else + { + /* This is a completely wierd case. In order to stuff in the + names that might contain colons (the usual name delimiter), + Mike Tiemann defined a different name format which is + signalled if the identifier is "op$". In that case, the + format is "op$::XXXX." where XXXX is the name. This is + used for names like "+" or "=". YUUUUUUUK! FIXME! */ + *pp = p + 2; + for (p = *pp; *p != '.' && *p != '\0'; p++) + ; + if (*p != '.') + { + bad_stab (orig); + return false; + } + name = savestring (*pp, p - *pp); + *pp = p + 1; + } + + allocvars = 10; + variants = ((debug_method_variant *) + xmalloc (allocvars * sizeof *variants)); + cvars = 0; + + look_ahead_type = DEBUG_TYPE_NULL; + + do + { + debug_type type; + boolean stub; + char *argtypes; + enum debug_visibility visibility; + boolean constp, volatilep, staticp; + bfd_vma voffset; + debug_type context; + const char *physname; + boolean varargs; + + if (look_ahead_type != DEBUG_TYPE_NULL) + { + /* g++ version 1 kludge */ + type = look_ahead_type; + look_ahead_type = DEBUG_TYPE_NULL; + } + else + { + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return false; + if (**pp != ':') + { + bad_stab (orig); + return false; + } + } + + ++*pp; + p = strchr (*pp, ';'); + if (p == NULL) + { + bad_stab (orig); + return false; + } + + stub = false; + if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD + && debug_get_parameter_types (dhandle, type, &varargs) == NULL) + stub = true; + + argtypes = savestring (*pp, p - *pp); + *pp = p + 1; + + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + default: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + + constp = false; + volatilep = false; + switch (**pp) + { + case 'A': + /* Normal function. */ + ++*pp; + break; + case 'B': + /* const member function. */ + constp = true; + ++*pp; + break; + case 'C': + /* volatile member function. */ + volatilep = true; + ++*pp; + break; + case 'D': + /* const volatile member function. */ + constp = true; + volatilep = true; + ++*pp; + break; + case '*': + case '?': + case '.': + /* File compiled with g++ version 1; no information. */ + break; + default: + warn_stab (orig, "const/volatile indicator missing"); + break; + } + + staticp = false; + switch (**pp) + { + case '*': + /* virtual member function, followed by index. The sign + bit is supposedly set to distinguish + pointers-to-methods from virtual function indicies. */ + ++*pp; + voffset = parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return false; + } + ++*pp; + voffset &= 0x7fffffff; + + if (**pp == ';' || *pp == '\0') + { + /* Must be g++ version 1. */ + context = DEBUG_TYPE_NULL; + } + else + { + /* Figure out from whence this virtual function + came. It may belong to virtual function table of + one of its baseclasses. */ + look_ahead_type = parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL); + if (**pp == ':') + { + /* g++ version 1 overloaded methods. */ + context = DEBUG_TYPE_NULL; + } + else + { + context = look_ahead_type; + look_ahead_type = DEBUG_TYPE_NULL; + if (**pp != ';') + { + bad_stab (orig); + return false; + } + ++*pp; + } + } + break; + + case '?': + /* static member function. */ + ++*pp; + staticp = true; + voffset = 0; + context = DEBUG_TYPE_NULL; + if (strncmp (argtypes, name, strlen (name)) != 0) + stub = true; + break; + + default: + warn_stab (orig, "member function type missing"); + voffset = 0; + context = DEBUG_TYPE_NULL; + break; + + case '.': + ++*pp; + voffset = 0; + context = DEBUG_TYPE_NULL; + break; + } + + /* If the type is not a stub, then the argtypes string is + the physical name of the function. Otherwise the + argtypes string is the mangled form of the argument + types, and the full type and the physical name must be + extracted from them. */ + if (! stub) + physname = argtypes; + else + { + debug_type class_type, return_type; + + class_type = stab_find_type (dhandle, info, typenums); + if (class_type == DEBUG_TYPE_NULL) + return false; + return_type = debug_get_return_type (dhandle, type); + if (return_type == DEBUG_TYPE_NULL) + { + bad_stab (orig); + return false; + } + type = parse_stab_argtypes (dhandle, info, class_type, name, + tagname, return_type, argtypes, + constp, volatilep, &physname); + if (type == DEBUG_TYPE_NULL) + return false; + } + + if (cvars + 1 >= allocvars) + { + allocvars += 10; + variants = ((debug_method_variant *) + xrealloc ((PTR) variants, + allocvars * sizeof *variants)); + } + + if (! staticp) + variants[cvars] = debug_make_method_variant (dhandle, physname, + type, visibility, + constp, volatilep, + voffset, context); + else + variants[cvars] = debug_make_static_method_variant (dhandle, + physname, + type, + visibility, + constp, + volatilep); + if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL) + return false; + + ++cvars; + } + while (**pp != ';' && **pp != '\0'); + + variants[cvars] = DEBUG_METHOD_VARIANT_NULL; + + if (**pp != '\0') + ++*pp; + + if (c + 1 >= alloc) + { + alloc += 10; + methods = ((debug_method *) + xrealloc ((PTR) methods, alloc * sizeof *methods)); + } + + methods[c] = debug_make_method (dhandle, name, variants); + + ++c; + } + + if (methods != NULL) + methods[c] = DEBUG_METHOD_NULL; + + *retp = methods; + + return true; +} + +/* Parse a string representing argument types for a method. Stabs + tries to save space by packing argument types into a mangled + string. This string should give us enough information to extract + both argument types and the physical name of the function, given + the tag name. */ + +static debug_type +parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname, + return_type, argtypes, constp, volatilep, pphysname) + PTR dhandle; + struct stab_handle *info; + debug_type class_type; + const char *fieldname; + const char *tagname; + debug_type return_type; + const char *argtypes; + boolean constp; + boolean volatilep; + const char **pphysname; +{ + boolean is_full_physname_constructor; + boolean is_constructor; + boolean is_destructor; + debug_type *args; + boolean varargs; + + /* Constructors are sometimes handled specially. */ + is_full_physname_constructor = ((argtypes[0] == '_' + && argtypes[1] == '_' + && (isdigit ((unsigned char) argtypes[2]) + || argtypes[2] == 'Q' + || argtypes[2] == 't')) + || strncmp (argtypes, "__ct", 4) == 0); + + is_constructor = (is_full_physname_constructor + || (tagname != NULL + && strcmp (fieldname, tagname) == 0)); + is_destructor = ((argtypes[0] == '_' + && (argtypes[1] == '$' || argtypes[1] == '.') + && argtypes[2] == '_') + || strncmp (argtypes, "__dt", 4) == 0); + + if (is_destructor || is_full_physname_constructor) + *pphysname = argtypes; + else + { + unsigned int len; + const char *const_prefix; + const char *volatile_prefix; + char buf[20]; + unsigned int mangled_name_len; + char *physname; + + len = tagname == NULL ? 0 : strlen (tagname); + const_prefix = constp ? "C" : ""; + volatile_prefix = volatilep ? "V" : ""; + + if (len == 0) + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + else if (tagname != NULL && strchr (tagname, '<') != NULL) + { + /* Template methods are fully mangled. */ + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + tagname = NULL; + len = 0; + } + else + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + + mangled_name_len = ((is_constructor ? 0 : strlen (fieldname)) + + strlen (buf) + + len + + strlen (argtypes) + + 1); + + if (fieldname[0] == 'o' + && fieldname[1] == 'p' + && (fieldname[2] == '$' || fieldname[2] == '.')) + { + const char *opname; + + opname = cplus_mangle_opname (fieldname + 3, 0); + if (opname == NULL) + { + fprintf (stderr, "No mangling for \"%s\"\n", fieldname); + return DEBUG_TYPE_NULL; + } + mangled_name_len += strlen (opname); + physname = (char *) xmalloc (mangled_name_len); + strncpy (physname, fieldname, 3); + strcpy (physname + 3, opname); + } + else + { + physname = (char *) xmalloc (mangled_name_len); + if (is_constructor) + physname[0] = '\0'; + else + strcpy (physname, fieldname); + } + + strcat (physname, buf); + if (tagname != NULL) + strcat (physname, tagname); + strcat (physname, argtypes); + + *pphysname = physname; + } + + if (*argtypes == '\0' || is_destructor) + { + args = (debug_type *) xmalloc (sizeof *args); + *args = NULL; + return debug_make_method_type (dhandle, return_type, class_type, args, + false); + } + + args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs); + if (args == NULL) + return DEBUG_TYPE_NULL; + + return debug_make_method_type (dhandle, return_type, class_type, args, + varargs); +} + +/* The tail end of stabs for C++ classes that contain a virtual function + pointer contains a tilde, a %, and a type number. + The type number refers to the base class (possibly this class itself) which + contains the vtable pointer for the current class. + + This function is called when we have parsed all the method declarations, + so we can look for the vptr base class info. */ + +static boolean +parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr) + PTR dhandle; + struct stab_handle *info; + const char **pp; + const int *typenums; + debug_type *retvptrbase; + boolean *retownvptr; +{ + const char *orig; + const char *hold; + int vtypenums[2]; + + *retvptrbase = DEBUG_TYPE_NULL; + *retownvptr = false; + + orig = *pp; + + /* If we are positioned at a ';', then skip it. */ + if (**pp == ';') + ++*pp; + + if (**pp != '~') + return true; + + ++*pp; + + if (**pp == '=' || **pp == '+' || **pp == '-') + { + /* Obsolete flags that used to indicate the presence of + constructors and/or destructors. */ + ++*pp; + } + + if (**pp != '%') + return true; + + ++*pp; + + hold = *pp; + + /* The next number is the type number of the base class (possibly + our own class) which supplies the vtable for this class. */ + if (! parse_stab_type_number (pp, vtypenums)) + return false; + + if (vtypenums[0] == typenums[0] + && vtypenums[1] == typenums[1]) + *retownvptr = true; + else + { + debug_type vtype; + const char *p; + + *pp = hold; + + vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + for (p = *pp; *p != ';' && *p != '\0'; p++) + ; + if (*p != ';') + { + bad_stab (orig); + return false; + } + + *retvptrbase = vtype; + + *pp = p + 1; + } + + return true; +} + +/* Read a definition of an array type. */ + +static debug_type +parse_stab_array_type (dhandle, info, pp, stringp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + boolean stringp; +{ + const char *orig; + const char *p; + int typenums[2]; + debug_type index_type; + boolean adjustable; + bfd_signed_vma lower, upper; + debug_type element_type; + + /* Format of an array type: + "ar<index type>;lower;upper;<array_contents_type>". + OS9000: "arlower,upper;<array_contents_type>". + + Fortran adjustable arrays use Adigits or Tdigits for lower or upper; + for these, produce a type like float[][]. */ + + orig = *pp; + + /* FIXME: gdb checks os9k_stabs here. */ + + /* If the index type is type 0, we take it as int. */ + p = *pp; + if (! parse_stab_type_number (&p, typenums)) + return DEBUG_TYPE_NULL; + if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=') + { + index_type = debug_find_named_type (dhandle, "int"); + if (index_type == DEBUG_TYPE_NULL) + { + index_type = debug_make_int_type (dhandle, 4, false); + if (index_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + *pp = p; + } + else + { + index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + } + + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + adjustable = false; + + if (! isdigit ((unsigned char) **pp) && **pp != '-') + { + ++*pp; + adjustable = true; + } + + lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (! isdigit ((unsigned char) **pp) && **pp != '-') + { + ++*pp; + adjustable = true; + } + + upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (element_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (adjustable) + { + lower = 0; + upper = -1; + } + + return debug_make_array_type (dhandle, element_type, index_type, lower, + upper, stringp); +} + +/* This struct holds information about files we have seen using + N_BINCL. */ + +struct bincl_file +{ + /* The next N_BINCL file. */ + struct bincl_file *next; + /* The next N_BINCL on the stack. */ + struct bincl_file *next_stack; + /* The file name. */ + const char *name; + /* The hash value. */ + bfd_vma hash; + /* The file index. */ + unsigned int file; + /* The list of types defined in this file. */ + struct stab_types *file_types; +}; + +/* Start a new N_BINCL file, pushing it onto the stack. */ + +static void +push_bincl (info, name, hash) + struct stab_handle *info; + const char *name; + bfd_vma hash; +{ + struct bincl_file *n; + + n = (struct bincl_file *) xmalloc (sizeof *n); + n->next = info->bincl_list; + n->next_stack = info->bincl_stack; + n->name = name; + n->hash = hash; + n->file = info->files; + n->file_types = NULL; + info->bincl_list = n; + info->bincl_stack = n; + + ++info->files; + info->file_types = ((struct stab_types **) + xrealloc ((PTR) info->file_types, + (info->files + * sizeof *info->file_types))); + info->file_types[n->file] = NULL; +} + +/* Finish an N_BINCL file, at an N_EINCL, popping the name off the + stack. */ + +static const char * +pop_bincl (info) + struct stab_handle *info; +{ + struct bincl_file *o; + + o = info->bincl_stack; + if (o == NULL) + return info->main_filename; + info->bincl_stack = o->next_stack; + + o->file_types = info->file_types[o->file]; + + if (info->bincl_stack == NULL) + return info->main_filename; + return info->bincl_stack->name; +} + +/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */ + +static boolean +find_excl (info, name, hash) + struct stab_handle *info; + const char *name; + bfd_vma hash; +{ + struct bincl_file *l; + + ++info->files; + info->file_types = ((struct stab_types **) + xrealloc ((PTR) info->file_types, + (info->files + * sizeof *info->file_types))); + + for (l = info->bincl_list; l != NULL; l = l->next) + if (l->hash == hash && strcmp (l->name, name) == 0) + break; + if (l == NULL) + { + warn_stab (name, "Undefined N_EXCL"); + info->file_types[info->files - 1] = NULL; + return true; + } + + info->file_types[info->files - 1] = l->file_types; + + return true; +} + +/* Handle a variable definition. gcc emits variable definitions for a + block before the N_LBRAC, so we must hold onto them until we see + it. The SunPRO compiler emits variable definitions after the + N_LBRAC, so we can call debug_record_variable immediately. */ + +static boolean +stab_record_variable (dhandle, info, name, type, kind, val) + PTR dhandle; + struct stab_handle *info; + const char *name; + debug_type type; + enum debug_var_kind kind; + bfd_vma val; +{ + struct stab_pending_var *v; + + if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) + || ! info->within_function + || (info->gcc_compiled == 0 && info->n_opt_found)) + return debug_record_variable (dhandle, name, type, kind, val); + + v = (struct stab_pending_var *) xmalloc (sizeof *v); + memset (v, 0, sizeof *v); + + v->next = info->pending; + v->name = name; + v->type = type; + v->kind = kind; + v->val = val; + info->pending = v; + + return true; +} + +/* Emit pending variable definitions. This is called after we see the + N_LBRAC that starts the block. */ + +static boolean +stab_emit_pending_vars (dhandle, info) + PTR dhandle; + struct stab_handle *info; +{ + struct stab_pending_var *v; + + v = info->pending; + while (v != NULL) + { + struct stab_pending_var *next; + + if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val)) + return false; + + next = v->next; + free (v); + v = next; + } + + info->pending = NULL; + + return true; +} + +/* Find the slot for a type in the database. */ + +static debug_type * +stab_find_slot (info, typenums) + struct stab_handle *info; + const int *typenums; +{ + int filenum; + int index; + struct stab_types **ps; + + filenum = typenums[0]; + index = typenums[1]; + + if (filenum < 0 || (unsigned int) filenum >= info->files) + { + fprintf (stderr, "Type file number %d out of range\n", filenum); + return NULL; + } + if (index < 0) + { + fprintf (stderr, "Type index number %d out of range\n", index); + return NULL; + } + + ps = info->file_types + filenum; + + while (index >= STAB_TYPES_SLOTS) + { + if (*ps == NULL) + { + *ps = (struct stab_types *) xmalloc (sizeof **ps); + memset (*ps, 0, sizeof **ps); + } + ps = &(*ps)->next; + index -= STAB_TYPES_SLOTS; + } + if (*ps == NULL) + { + *ps = (struct stab_types *) xmalloc (sizeof **ps); + memset (*ps, 0, sizeof **ps); + } + + return (*ps)->types + index; +} + +/* Find a type given a type number. If the type has not been + allocated yet, create an indirect type. */ + +static debug_type +stab_find_type (dhandle, info, typenums) + PTR dhandle; + struct stab_handle *info; + const int *typenums; +{ + debug_type *slot; + + if (typenums[0] == 0 && typenums[1] < 0) + { + /* A negative type number indicates an XCOFF builtin type. */ + return stab_xcoff_builtin_type (dhandle, info, typenums[1]); + } + + slot = stab_find_slot (info, typenums); + if (slot == NULL) + return DEBUG_TYPE_NULL; + + if (*slot == DEBUG_TYPE_NULL) + return debug_make_indirect_type (dhandle, slot, (const char *) NULL); + + return *slot; +} + +/* Record that a given type number refers to a given type. */ + +static boolean +stab_record_type (dhandle, info, typenums, type) + PTR dhandle; + struct stab_handle *info; + const int *typenums; + debug_type type; +{ + debug_type *slot; + + slot = stab_find_slot (info, typenums); + if (slot == NULL) + return false; + + /* gdb appears to ignore type redefinitions, so we do as well. */ + + *slot = type; + + return true; +} + +/* Return an XCOFF builtin type. */ + +static debug_type +stab_xcoff_builtin_type (dhandle, info, typenum) + PTR dhandle; + struct stab_handle *info; + int typenum; +{ + debug_type rettype; + const char *name; + + if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT) + { + fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum); + return DEBUG_TYPE_NULL; + } + if (info->xcoff_types[-typenum] != NULL) + return info->xcoff_types[-typenum]; + + switch (-typenum) + { + case 1: + /* The size of this and all the other types are fixed, defined + by the debugging format. */ + name = "int"; + rettype = debug_make_int_type (dhandle, 4, false); + break; + case 2: + name = "char"; + rettype = debug_make_int_type (dhandle, 1, false); + break; + case 3: + name = "short"; + rettype = debug_make_int_type (dhandle, 2, false); + break; + case 4: + name = "long"; + rettype = debug_make_int_type (dhandle, 4, false); + break; + case 5: + name = "unsigned char"; + rettype = debug_make_int_type (dhandle, 1, true); + break; + case 6: + name = "signed char"; + rettype = debug_make_int_type (dhandle, 1, false); + break; + case 7: + name = "unsigned short"; + rettype = debug_make_int_type (dhandle, 2, true); + break; + case 8: + name = "unsigned int"; + rettype = debug_make_int_type (dhandle, 4, true); + break; + case 9: + name = "unsigned"; + rettype = debug_make_int_type (dhandle, 4, true); + case 10: + name = "unsigned long"; + rettype = debug_make_int_type (dhandle, 4, true); + break; + case 11: + name = "void"; + rettype = debug_make_void_type (dhandle); + break; + case 12: + /* IEEE single precision (32 bit). */ + name = "float"; + rettype = debug_make_float_type (dhandle, 4); + break; + case 13: + /* IEEE double precision (64 bit). */ + name = "double"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 14: + /* This is an IEEE double on the RS/6000, and different machines + with different sizes for "long double" should use different + negative type numbers. See stabs.texinfo. */ + name = "long double"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 15: + name = "integer"; + rettype = debug_make_int_type (dhandle, 4, false); + break; + case 16: + name = "boolean"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 17: + name = "short real"; + rettype = debug_make_float_type (dhandle, 4); + break; + case 18: + name = "real"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 19: + /* FIXME */ + name = "stringptr"; + rettype = NULL; + break; + case 20: + /* FIXME */ + name = "character"; + rettype = debug_make_int_type (dhandle, 1, true); + break; + case 21: + name = "logical*1"; + rettype = debug_make_bool_type (dhandle, 1); + break; + case 22: + name = "logical*2"; + rettype = debug_make_bool_type (dhandle, 2); + break; + case 23: + name = "logical*4"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 24: + name = "logical"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 25: + /* Complex type consisting of two IEEE single precision values. */ + name = "complex"; + rettype = debug_make_complex_type (dhandle, 8); + break; + case 26: + /* Complex type consisting of two IEEE double precision values. */ + name = "double complex"; + rettype = debug_make_complex_type (dhandle, 16); + break; + case 27: + name = "integer*1"; + rettype = debug_make_int_type (dhandle, 1, false); + break; + case 28: + name = "integer*2"; + rettype = debug_make_int_type (dhandle, 2, false); + break; + case 29: + name = "integer*4"; + rettype = debug_make_int_type (dhandle, 4, false); + break; + case 30: + /* FIXME */ + name = "wchar"; + rettype = debug_make_int_type (dhandle, 2, false); + break; + case 31: + name = "long long"; + rettype = debug_make_int_type (dhandle, 8, false); + break; + case 32: + name = "unsigned long long"; + rettype = debug_make_int_type (dhandle, 8, true); + break; + case 33: + name = "logical*8"; + rettype = debug_make_bool_type (dhandle, 8); + break; + case 34: + name = "integer*8"; + rettype = debug_make_int_type (dhandle, 8, false); + break; + default: + abort (); + } + + rettype = debug_name_type (dhandle, name, rettype); + + info->xcoff_types[-typenum] = rettype; + + return rettype; +} + +/* Find or create a tagged type. */ + +static debug_type +stab_find_tagged_type (dhandle, info, p, len, kind) + PTR dhandle; + struct stab_handle *info; + const char *p; + int len; + enum debug_type_kind kind; +{ + char *name; + debug_type dtype; + struct stab_tag *st; + + name = savestring (p, len); + + /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same + namespace. This is right for C, and I don't know how to handle + other languages. FIXME. */ + dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL); + if (dtype != DEBUG_TYPE_NULL) + { + free (name); + return dtype; + } + + /* We need to allocate an entry on the undefined tag list. */ + for (st = info->tags; st != NULL; st = st->next) + { + if (st->name[0] == name[0] + && strcmp (st->name, name) == 0) + { + if (st->kind == DEBUG_KIND_ILLEGAL) + st->kind = kind; + free (name); + break; + } + } + if (st == NULL) + { + st = (struct stab_tag *) xmalloc (sizeof *st); + memset (st, 0, sizeof *st); + + st->next = info->tags; + st->name = name; + st->kind = kind; + st->slot = DEBUG_TYPE_NULL; + st->type = debug_make_indirect_type (dhandle, &st->slot, name); + info->tags = st; + } + + return st->type; +} + +/* In order to get the correct argument types for a stubbed method, we + need to extract the argument types from a C++ mangled string. + Since the argument types can refer back to the return type, this + means that we must demangle the entire physical name. In gdb this + is done by calling cplus_demangle and running the results back + through the C++ expression parser. Since we have no expression + parser, we must duplicate much of the work of cplus_demangle here. + + We assume that GNU style demangling is used, since this is only + done for method stubs, and only g++ should output that form of + debugging information. */ + +/* This structure is used to hold a pointer to type information which + demangling a string. */ + +struct stab_demangle_typestring +{ + /* The start of the type. This is not null terminated. */ + const char *typestring; + /* The length of the type. */ + unsigned int len; +}; + +/* This structure is used to hold information while demangling a + string. */ + +struct stab_demangle_info +{ + /* The debugging information handle. */ + PTR dhandle; + /* The stab information handle. */ + struct stab_handle *info; + /* The array of arguments we are building. */ + debug_type *args; + /* Whether the method takes a variable number of arguments. */ + boolean varargs; + /* The array of types we have remembered. */ + struct stab_demangle_typestring *typestrings; + /* The number of typestrings. */ + unsigned int typestring_count; + /* The number of typestring slots we have allocated. */ + unsigned int typestring_alloc; +}; + +static void stab_bad_demangle PARAMS ((const char *)); +static unsigned int stab_demangle_count PARAMS ((const char **)); +static boolean stab_demangle_get_count + PARAMS ((const char **, unsigned int *)); +static boolean stab_demangle_prefix + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_function_name + PARAMS ((struct stab_demangle_info *, const char **, const char *)); +static boolean stab_demangle_signature + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_qualified + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_template + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_class + PARAMS ((struct stab_demangle_info *, const char **, const char **)); +static boolean stab_demangle_args + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + boolean *)); +static boolean stab_demangle_arg + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + unsigned int *, unsigned int *)); +static boolean stab_demangle_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_fund_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_remember_type + PARAMS ((struct stab_demangle_info *, const char *, int)); + +/* Warn about a bad demangling. */ + +static void +stab_bad_demangle (s) + const char *s; +{ + fprintf (stderr, "bad mangled name `%s'\n", s); +} + +/* Get a count from a stab string. */ + +static unsigned int +stab_demangle_count (pp) + const char **pp; +{ + unsigned int count; + + count = 0; + while (isdigit ((unsigned char) **pp)) + { + count *= 10; + count += **pp - '0'; + ++*pp; + } + return count; +} + +/* Require a count in a string. The count may be multiple digits, in + which case it must end in an underscore. */ + +static boolean +stab_demangle_get_count (pp, pi) + const char **pp; + unsigned int *pi; +{ + if (! isdigit ((unsigned char) **pp)) + return false; + + *pi = **pp - '0'; + ++*pp; + if (isdigit ((unsigned char) **pp)) + { + unsigned int count; + const char *p; + + count = *pi; + p = *pp; + do + { + count *= 10; + count += *p - '0'; + ++p; + } + while (isdigit ((unsigned char) *p)); + if (*p == '_') + { + *pp = p + 1; + *pi = count; + } + } + + return true; +} + +/* This function demangles a physical name, returning a NULL + terminated array of argument types. */ + +static debug_type * +stab_demangle_argtypes (dhandle, info, physname, pvarargs) + PTR dhandle; + struct stab_handle *info; + const char *physname; + boolean *pvarargs; +{ + struct stab_demangle_info minfo; + + minfo.dhandle = dhandle; + minfo.info = info; + minfo.args = NULL; + minfo.varargs = false; + minfo.typestring_alloc = 10; + minfo.typestrings = ((struct stab_demangle_typestring *) + xmalloc (minfo.typestring_alloc + * sizeof *minfo.typestrings)); + minfo.typestring_count = 0; + + /* cplus_demangle checks for special GNU mangled forms, but we can't + see any of them in mangled method argument types. */ + + if (! stab_demangle_prefix (&minfo, &physname)) + goto error_return; + + if (*physname != '\0') + { + if (! stab_demangle_signature (&minfo, &physname)) + goto error_return; + } + + free (minfo.typestrings); + minfo.typestrings = NULL; + + if (minfo.args == NULL) + fprintf (stderr, "no argument types in mangled string\n"); + + *pvarargs = minfo.varargs; + return minfo.args; + + error_return: + if (minfo.typestrings != NULL) + free (minfo.typestrings); + return NULL; +} + +/* Demangle the prefix of the mangled name. */ + +static boolean +stab_demangle_prefix (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *scan; + unsigned int i; + + /* cplus_demangle checks for global constructors and destructors, + but we can't see them in mangled argument types. */ + + /* Look for `__'. */ + scan = *pp; + do + { + scan = strchr (scan, '_'); + } + while (scan != NULL && *++scan != '_'); + + if (scan == NULL) + { + stab_bad_demangle (*pp); + return false; + } + + --scan; + + /* We found `__'; move ahead to the last contiguous `__' pair. */ + i = strspn (scan, "_"); + if (i > 2) + scan += i - 2; + + if (scan == *pp + && (isdigit ((unsigned char) scan[2]) + || scan[2] == 'Q' + || scan[2] == 't')) + { + /* This is a GNU style constructor name. */ + *pp = scan + 2; + return true; + } + else if (scan == *pp + && ! isdigit ((unsigned char) scan[2]) + && scan[2] != 't') + { + /* Look for the `__' that separates the prefix from the + signature. */ + while (*scan == '_') + ++scan; + scan = strstr (scan, "__"); + if (scan == NULL || scan[2] == '\0') + { + stab_bad_demangle (*pp); + return false; + } + + return stab_demangle_function_name (minfo, pp, scan); + } + else if (scan[2] != '\0') + { + /* The name doesn't start with `__', but it does contain `__'. */ + return stab_demangle_function_name (minfo, pp, scan); + } + else + { + stab_bad_demangle (*pp); + return false; + } + /*NOTREACHED*/ +} + +/* Demangle a function name prefix. The scan argument points to the + double underscore which separates the function name from the + signature. */ + +static boolean +stab_demangle_function_name (minfo, pp, scan) + struct stab_demangle_info *minfo; + const char **pp; + const char *scan; +{ + const char *name; + + /* The string from *pp to scan is the name of the function. We + don't care about the name, since we just looking for argument + types. However, for conversion operators, the name may include a + type which we must remember in order to handle backreferences. */ + + name = *pp; + *pp = scan + 2; + + if (*pp - name >= 5 + && strncmp (name, "type", 4) == 0 + && (name[4] == '$' || name[4] == '.')) + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 5; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return false; + } + else if (name[0] == '_' + && name[1] == '_' + && name[2] == 'o' + && name[3] == 'p') + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 4; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return false; + } + + return true; +} + +/* Demangle the signature. This is where the argument types are + found. */ + +static boolean +stab_demangle_signature (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *orig; + boolean expect_func, func_done; + const char *hold; + + orig = *pp; + + expect_func = false; + func_done = false; + hold = NULL; + + while (**pp != '\0') + { + switch (**pp) + { + case 'Q': + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + expect_func = true; + hold = NULL; + break; + + case 'S': + /* Static member function. FIXME: Can this happen? */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case 'C': + /* Const member function. */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (hold == NULL) + hold = *pp; + if (! stab_demangle_class (minfo, pp, (const char **) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + expect_func = true; + hold = NULL; + break; + + case 'F': + /* Function. I don't know if this actually happens with g++ + output. */ + hold = NULL; + func_done = true; + ++*pp; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + break; + + case 't': + /* Template. */ + if (hold == NULL) + hold = *pp; + if (! stab_demangle_template (minfo, pp) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + hold = NULL; + expect_func = true; + break; + + case '_': + /* At the outermost level, we cannot have a return type + specified, so if we run into another '_' at this point we + are dealing with a mangled name that is either bogus, or + has been mangled by some algorithm we don't know how to + deal with. So just reject the entire demangling. */ + stab_bad_demangle (orig); + return false; + + default: + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = true; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + break; + } + + if (expect_func) + { + func_done = true; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + } + } + + if (! func_done) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added + to the current declp. */ + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + } + + return true; +} + +/* Demangle a qualified name, such as "Q25Outer5Inner" which is the + mangled form of "Outer::Inner". */ + +static boolean +stab_demangle_qualified (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + const char *p; + unsigned int qualifiers; + debug_type context; + + orig = *pp; + + switch ((*pp)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is + preceded by an underscore (to distinguish it from the <= 9 + case) and followed by an underscore. */ + p = *pp + 2; + if (! isdigit ((unsigned char) *p) || *p == '0') + { + stab_bad_demangle (orig); + return false; + } + qualifiers = atoi (p); + while (isdigit ((unsigned char) *p)) + ++p; + if (*p != '_') + { + stab_bad_demangle (orig); + return false; + } + *pp = p + 1; + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + qualifiers = (*pp)[1] - '0'; + /* Skip an optional underscore after the count. */ + if ((*pp)[2] == '_') + ++*pp; + *pp += 2; + break; + + case '0': + default: + stab_bad_demangle (orig); + return false; + } + + context = DEBUG_TYPE_NULL; + + /* Pick off the names. */ + while (qualifiers-- > 0) + { + if (**pp == '_') + ++*pp; + if (**pp == 't') + { + /* FIXME: I don't know how to handle the ptype != NULL case + here. */ + if (! stab_demangle_template (minfo, pp)) + return false; + } + else + { + unsigned int len; + + len = stab_demangle_count (pp); + if (strlen (*pp) < len) + { + stab_bad_demangle (orig); + return false; + } + + if (ptype != NULL) + { + const debug_field *fields; + + fields = NULL; + if (context != DEBUG_TYPE_NULL) + fields = debug_get_fields (minfo->dhandle, context); + + context = DEBUG_TYPE_NULL; + + if (fields != NULL) + { + char *name; + + /* Try to find the type by looking through the + fields of context until we find a field with the + same type. This ought to work for a class + defined within a class, but it won't work for, + e.g., an enum defined within a class. stabs does + not give us enough information to figure out the + latter case. */ + + name = savestring (*pp, len); + + for (; *fields != DEBUG_FIELD_NULL; fields++) + { + debug_type ft; + const char *dn; + + ft = debug_get_field_type (minfo->dhandle, *fields); + if (ft == NULL) + return false; + dn = debug_get_type_name (minfo->dhandle, ft); + if (dn != NULL && strcmp (dn, name) == 0) + { + context = ft; + break; + } + } + + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + /* We have to fall back on finding the type by name. + If there are more types to come, then this must + be a class. Otherwise, it could be anything. */ + + if (qualifiers == 0) + { + char *name; + + name = savestring (*pp, len); + context = debug_find_named_type (minfo->dhandle, + name); + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + context = stab_find_tagged_type (minfo->dhandle, + minfo->info, + *pp, len, + (qualifiers == 0 + ? DEBUG_KIND_ILLEGAL + : DEBUG_KIND_CLASS)); + if (context == DEBUG_TYPE_NULL) + return false; + } + } + } + + *pp += len; + } + } + + if (ptype != NULL) + *ptype = context; + + return true; +} + +/* Demangle a template. */ + +static boolean +stab_demangle_template (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *orig; + unsigned int r, i; + + orig = *pp; + + ++*pp; + + /* Skip the template name. */ + r = stab_demangle_count (pp); + if (r == 0 || strlen (*pp) < r) + { + stab_bad_demangle (orig); + return false; + } + *pp += r; + + /* Get the size of the parameter list. */ + if (stab_demangle_get_count (pp, &r) == 0) + { + stab_bad_demangle (orig); + return false; + } + + for (i = 0; i < r; i++) + { + if (**pp == 'Z') + { + /* This is a type parameter. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return false; + } + else + { + const char *old_p; + boolean pointerp, realp, integralp, charp, boolp; + boolean done; + + old_p = *pp; + pointerp = false; + realp = false; + integralp = false; + charp = false; + boolp = false; + done = false; + + /* This is a value parameter. */ + + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return false; + + while (*old_p != '\0' && ! done) + { + switch (*old_p) + { + case 'P': + case 'p': + case 'R': + pointerp = true; + done = true; + break; + case 'C': /* Const. */ + case 'S': /* Signed. */ + case 'U': /* Unsigned. */ + case 'V': /* Volatile. */ + case 'F': /* Function. */ + case 'M': /* Member function. */ + case 'O': /* ??? */ + ++old_p; + break; + case 'Q': /* Qualified name. */ + integralp = true; + done = true; + break; + case 'T': /* Remembered type. */ + abort (); + case 'v': /* Void. */ + abort (); + case 'x': /* Long long. */ + case 'l': /* Long. */ + case 'i': /* Int. */ + case 's': /* Short. */ + case 'w': /* Wchar_t. */ + integralp = true; + done = true; + break; + case 'b': /* Bool. */ + boolp = true; + done = true; + break; + case 'c': /* Char. */ + charp = true; + done = true; + break; + case 'r': /* Long double. */ + case 'd': /* Double. */ + case 'f': /* Float. */ + realp = true; + done = true; + break; + default: + /* Assume it's a user defined integral type. */ + integralp = true; + done = true; + break; + } + } + + if (integralp) + { + if (**pp == 'm') + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + else if (charp) + { + unsigned int val; + + if (**pp == 'm') + ++*pp; + val = stab_demangle_count (pp); + if (val == 0) + { + stab_bad_demangle (orig); + return false; + } + } + else if (boolp) + { + unsigned int val; + + val = stab_demangle_count (pp); + if (val != 0 && val != 1) + { + stab_bad_demangle (orig); + return false; + } + } + else if (realp) + { + if (**pp == 'm') + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + if (**pp == '.') + { + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + if (**pp == 'e') + { + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + } + else if (pointerp) + { + unsigned int len; + + if (! stab_demangle_get_count (pp, &len)) + { + stab_bad_demangle (orig); + return false; + } + *pp += len; + } + } + } + + return true; +} + +/* Demangle a class name. */ + +static boolean +stab_demangle_class (minfo, pp, pstart) + struct stab_demangle_info *minfo; + const char **pp; + const char **pstart; +{ + const char *orig; + unsigned int n; + + orig = *pp; + + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return false; + } + + if (pstart != NULL) + *pstart = *pp; + + *pp += n; + + return true; +} + +/* Demangle function arguments. If the pargs argument is not NULL, it + is set to a NULL terminated array holding the arguments. */ + +static boolean +stab_demangle_args (minfo, pp, pargs, pvarargs) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + boolean *pvarargs; +{ + const char *orig; + unsigned int alloc, count; + + orig = *pp; + + alloc = 10; + if (pargs != NULL) + { + *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs); + *pvarargs = false; + } + count = 0; + + while (**pp != '_' && **pp != '\0' && **pp != 'e') + { + if (**pp == 'N' || **pp == 'T') + { + char temptype; + unsigned int r, t; + + temptype = **pp; + ++*pp; + + if (temptype == 'T') + r = 1; + else + { + if (! stab_demangle_get_count (pp, &r)) + { + stab_bad_demangle (orig); + return false; + } + } + + if (! stab_demangle_get_count (pp, &t)) + { + stab_bad_demangle (orig); + return false; + } + + if (t >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return false; + } + while (r-- > 0) + { + const char *tem; + + tem = minfo->typestrings[t].typestring; + if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc)) + return false; + } + } + else + { + if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc)) + return false; + } + } + + if (pargs != NULL) + (*pargs)[count] = DEBUG_TYPE_NULL; + + if (**pp == 'e') + { + if (pargs != NULL) + *pvarargs = true; + ++*pp; + } + + return true; +} + +/* Demangle a single argument. */ + +static boolean +stab_demangle_arg (minfo, pp, pargs, pcount, palloc) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + unsigned int *pcount; + unsigned int *palloc; +{ + const char *start; + debug_type type; + + start = *pp; + if (! stab_demangle_type (minfo, pp, + pargs == NULL ? (debug_type *) NULL : &type) + || ! stab_demangle_remember_type (minfo, start, *pp - start)) + return false; + + if (pargs != NULL) + { + if (type == DEBUG_TYPE_NULL) + return false; + + if (*pcount + 1 >= *palloc) + { + *palloc += 10; + *pargs = ((debug_type *) + xrealloc (*pargs, *palloc * sizeof **pargs)); + } + (*pargs)[*pcount] = type; + ++*pcount; + } + + return true; +} + +/* Demangle a type. If the ptype argument is not NULL, *ptype is set + to the newly allocated type. */ + +static boolean +stab_demangle_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + + orig = *pp; + + switch (**pp) + { + case 'P': + case 'p': + /* A pointer type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_pointer_type (minfo->dhandle, *ptype); + break; + + case 'R': + /* A reference type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_reference_type (minfo->dhandle, *ptype); + break; + + case 'A': + /* An array. */ + { + unsigned long high; + + ++*pp; + high = 0; + while (**pp != '\0' && **pp != '_') + { + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + high *= 10; + high += **pp - '0'; + ++*pp; + } + if (**pp != '_') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + { + debug_type int_type; + + int_type = debug_find_named_type (minfo->dhandle, "int"); + if (int_type == NULL) + int_type = debug_make_int_type (minfo->dhandle, 4, false); + *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type, + 0, high, false); + } + } + break; + + case 'T': + /* A back reference to a remembered type. */ + { + unsigned int i; + const char *p; + + ++*pp; + if (! stab_demangle_get_count (pp, &i)) + { + stab_bad_demangle (orig); + return false; + } + if (i >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return false; + } + p = minfo->typestrings[i].typestring; + if (! stab_demangle_type (minfo, &p, ptype)) + return false; + } + break; + + case 'F': + /* A function. */ + { + debug_type *args; + boolean varargs; + + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (boolean *) NULL + : &varargs))) + return false; + if (**pp != '_') + { + /* cplus_demangle will accept a function without a return + type, but I don't know when that will happen, or what + to do if it does. */ + stab_bad_demangle (orig); + return false; + } + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_function_type (minfo->dhandle, *ptype, args, + varargs); + + } + break; + + case 'M': + case 'O': + { + boolean memberp, constp, volatilep; + debug_type *args; + boolean varargs; + unsigned int n; + const char *name; + + memberp = **pp == 'M'; + constp = false; + volatilep = false; + args = NULL; + varargs = false; + + ++*pp; + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return false; + } + name = *pp; + *pp += n; + + if (memberp) + { + if (**pp == 'C') + { + constp = true; + ++*pp; + } + else if (**pp == 'V') + { + volatilep = true; + ++*pp; + } + if (**pp != 'F') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (boolean *) NULL + : &varargs))) + return false; + } + + if (**pp != '_') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + + if (ptype != NULL) + { + debug_type class_type; + + class_type = stab_find_tagged_type (minfo->dhandle, minfo->info, + name, (int) n, + DEBUG_KIND_CLASS); + if (class_type == DEBUG_TYPE_NULL) + return false; + + if (! memberp) + *ptype = debug_make_offset_type (minfo->dhandle, class_type, + *ptype); + else + { + /* FIXME: We have no way to record constp or + volatilep. */ + *ptype = debug_make_method_type (minfo->dhandle, *ptype, + class_type, args, varargs); + } + } + } + break; + + case 'G': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + break; + + case 'C': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + break; + + case 'Q': + { + const char *hold; + + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, ptype)) + return false; + } + break; + + default: + if (! stab_demangle_fund_type (minfo, pp, ptype)) + return false; + break; + } + + return true; +} + +/* Demangle a fundamental type. If the ptype argument is not NULL, + *ptype is set to the newly allocated type. */ + +static boolean +stab_demangle_fund_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + boolean constp, volatilep, unsignedp, signedp; + boolean done; + + orig = *pp; + + constp = false; + volatilep = false; + unsignedp = false; + signedp = false; + + done = false; + while (! done) + { + switch (**pp) + { + case 'C': + constp = true; + ++*pp; + break; + + case 'U': + unsignedp = true; + ++*pp; + break; + + case 'S': + signedp = true; + ++*pp; + break; + + case 'V': + volatilep = true; + ++*pp; + break; + + default: + done = true; + break; + } + } + + switch (**pp) + { + case '\0': + case '_': + /* cplus_demangle permits this, but I don't know what it means. */ + stab_bad_demangle (orig); + break; + + case 'v': /* void */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "void"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_void_type (minfo->dhandle); + } + ++*pp; + break; + + case 'x': /* long long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long long unsigned int" + : "long long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp); + } + ++*pp; + break; + + case 'l': /* long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long unsigned int" + : "long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 'i': /* int */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned int" + : "int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 's': /* short */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "short unsigned int" + : "short int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp); + } + ++*pp; + break; + + case 'b': /* bool */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "bool"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_bool_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'c': /* char */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned char" + : (signedp + ? "signed char" + : "char"))); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp); + } + ++*pp; + break; + + case 'w': /* wchar_t */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, true); + } + ++*pp; + break; + + case 'r': /* long double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "long double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'd': /* double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'f': /* float */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "float"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'G': + ++*pp; + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + /* Fall through. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + const char *hold; + + if (! stab_demangle_class (minfo, pp, &hold)) + return false; + if (ptype != NULL) + { + char *name; + + name = savestring (hold, *pp - hold); + *ptype = debug_find_named_type (minfo->dhandle, name); + if (*ptype == DEBUG_TYPE_NULL) + { + /* FIXME: It is probably incorrect to assume that + undefined types are tagged types. */ + *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info, + hold, *pp - hold, + DEBUG_KIND_ILLEGAL); + } + free (name); + } + } + break; + + case 't': + if (! stab_demangle_template (minfo, pp)) + return false; + if (ptype != NULL) + { + debug_type t; + + /* FIXME: I really don't know how a template should be + represented in the current type system. Perhaps the + template should be demangled into a string, and the type + should be represented as a named type. However, I don't + know what the base type of the named type should be. */ + t = debug_make_void_type (minfo->dhandle); + t = debug_make_pointer_type (minfo->dhandle, t); + t = debug_name_type (minfo->dhandle, "TEMPLATE", t); + *ptype = t; + } + break; + + default: + stab_bad_demangle (orig); + return false; + } + + if (ptype != NULL) + { + if (constp) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + if (volatilep) + *ptype = debug_make_volatile_type (minfo->dhandle, *ptype); + } + + return true; +} + +/* Remember a type string in a demangled string. */ + +static boolean +stab_demangle_remember_type (minfo, p, len) + struct stab_demangle_info *minfo; + const char *p; + int len; +{ + if (minfo->typestring_count >= minfo->typestring_alloc) + { + minfo->typestring_alloc += 10; + minfo->typestrings = ((struct stab_demangle_typestring *) + xrealloc (minfo->typestrings, + (minfo->typestring_alloc + * sizeof *minfo->typestrings))); + } + + minfo->typestrings[minfo->typestring_count].typestring = p; + minfo->typestrings[minfo->typestring_count].len = (unsigned int) len; + ++minfo->typestring_count; + + return true; +} diff --git a/readline/callback.c b/readline/callback.c index 6915be483a4..200f3cc37f9 100644 --- a/readline/callback.c +++ b/readline/callback.c @@ -29,6 +29,7 @@ #if defined (READLINE_CALLBACKS) +#include <stdlib.h> #include <sys/types.h> #include <stdio.h> diff --git a/readline/complete.c b/readline/complete.c index ade317ff578..d003c2db75b 100644 --- a/readline/complete.c +++ b/readline/complete.c @@ -291,14 +291,14 @@ rl_complete (ignore, invoking_key) /* List the possible completions. See description of rl_complete (). */ int rl_possible_completions (ignore, invoking_key) - int ignore, invoking_key; + int ignore __attribute__((unused)), invoking_key __attribute__((unused)); { return (rl_complete_internal ('?')); } int rl_insert_completions (ignore, invoking_key) - int ignore, invoking_key; + int ignore __attribute__((unused)), invoking_key __attribute__((unused)); { return (rl_complete_internal ('*')); } diff --git a/readline/readline.c b/readline/readline.c index 622811fc11e..71a2320c582 100644 --- a/readline/readline.c +++ b/readline/readline.c @@ -914,7 +914,7 @@ rl_digit_loop () /* Add the current digit to the argument in progress. */ int rl_digit_argument (ignore, key) - int ignore, key; + int ignore __attribute__((unused)), key; { rl_pending_input = key; return (rl_digit_loop ()); @@ -944,7 +944,7 @@ _rl_init_argument () dispatch on it. If the key is the abort character then abort. */ int rl_universal_argument (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { rl_numeric_arg *= 4; return (rl_digit_loop ()); @@ -1147,7 +1147,7 @@ rl_backward (count, key) /* Move to the beginning of the line. */ int rl_beg_of_line (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { rl_point = 0; return 0; @@ -1156,7 +1156,7 @@ rl_beg_of_line (count, key) /* Move to the end of the line. */ int rl_end_of_line (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { rl_point = rl_end; return 0; @@ -1253,7 +1253,7 @@ rl_backward_word (count, key) /* Clear the current line. Numeric argument to C-l does this. */ int rl_refresh_line (ignore1, ignore2) - int ignore1, ignore2; + int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); { int curr_line, nleft; @@ -1313,7 +1313,7 @@ rl_clear_screen (count, key) int rl_arrow_keys (count, c) - int count, c; + int count, c __attribute__((unused)); { int ch; @@ -1417,7 +1417,7 @@ rl_insert (count, c) /* Insert the next typed character verbatim. */ int rl_quoted_insert (count, key) - int count, key; + int count, key __attribute__((unused)); { int c; @@ -1428,7 +1428,7 @@ rl_quoted_insert (count, key) /* Insert a tab character. */ int rl_tab_insert (count, key) - int count, key; + int count, key __attribute__((unused)); { return (rl_insert (count, '\t')); } @@ -1438,7 +1438,7 @@ rl_tab_insert (count, key) meaning in the future. */ int rl_newline (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { rl_done = 1; @@ -1466,7 +1466,7 @@ rl_newline (count, key) is special cased. */ int rl_do_lowercase_version (ignore1, ignore2) - int ignore1, ignore2; + int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); { return 0; } @@ -1553,7 +1553,7 @@ rl_rubout_or_delete (count, key) /* Delete all spaces and tabs around point. */ int rl_delete_horizontal_space (count, ignore) - int count, ignore; + int count __attribute__((unused)), ignore __attribute__((unused)); { int start = rl_point; @@ -1594,7 +1594,7 @@ rl_delete_or_show_completions (count, key) A K*rn shell style function. */ int rl_insert_comment (count, key) - int count, key; + int count __attribute__((unused)), key; { rl_beg_of_line (1, key); rl_insert_text (_rl_comment_begin ? _rl_comment_begin @@ -1620,7 +1620,7 @@ static int rl_change_case (); /* Uppercase the word at point. */ int rl_upcase_word (count, key) - int count, key; + int count, key __attribute__((unused)); { return (rl_change_case (count, UpCase)); } @@ -1628,7 +1628,7 @@ rl_upcase_word (count, key) /* Lowercase the word at point. */ int rl_downcase_word (count, key) - int count, key; + int count, key __attribute__((unused)); { return (rl_change_case (count, DownCase)); } @@ -1636,7 +1636,7 @@ rl_downcase_word (count, key) /* Upcase the first letter, downcase the rest. */ int rl_capitalize_word (count, key) - int count, key; + int count, key __attribute__((unused)); { return (rl_change_case (count, CapCase)); } @@ -1760,7 +1760,7 @@ rl_transpose_words (count, key) then transpose the characters before point. */ int rl_transpose_chars (count, key) - int count, key; + int count, key __attribute__((unused)); { char dummy[2]; @@ -1853,14 +1853,14 @@ _rl_char_search (count, fdir, bdir) int rl_char_search (count, key) - int count, key; + int count, key __attribute__((unused)); { return (_rl_char_search (count, FFIND, BFIND)); } int rl_backward_char_search (count, key) - int count, key; + int count, key __attribute__((unused)); { return (_rl_char_search (count, BFIND, FFIND)); } @@ -1965,7 +1965,7 @@ maybe_save_line () /* Meta-< goes to the start of the history. */ int rl_beginning_of_history (count, key) - int count, key; + int count __attribute__((unused)), key; { return (rl_get_previous_history (1 + where_history (), key)); } @@ -1973,7 +1973,7 @@ rl_beginning_of_history (count, key) /* Meta-> goes to the end of the history. (The current line). */ int rl_end_of_history (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { maybe_replace_line (); using_history (); @@ -2105,7 +2105,7 @@ _rl_set_mark_at_pos (position) /* A bindable command to set the mark. */ int rl_set_mark (count, key) - int count, key; + int count, key __attribute__((unused)); { return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); } @@ -2113,7 +2113,7 @@ rl_set_mark (count, key) /* Exchange the position of mark and point. */ int rl_exchange_point_and_mark (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { if (rl_mark > rl_end) rl_mark = -1; @@ -2137,7 +2137,7 @@ rl_exchange_point_and_mark (count, key) /* How to toggle back and forth between editing modes. */ int rl_vi_editing_mode (count, key) - int count, key; + int count __attribute__((unused)), key; { #if defined (VI_MODE) rl_editing_mode = vi_mode; @@ -2148,7 +2148,7 @@ rl_vi_editing_mode (count, key) int rl_emacs_editing_mode (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { rl_editing_mode = emacs_mode; _rl_keymap = emacs_standard_keymap; diff --git a/readline/vi_mode.c b/readline/vi_mode.c index d4868bf3b13..d62d91dada6 100644 --- a/readline/vi_mode.c +++ b/readline/vi_mode.c @@ -136,7 +136,7 @@ static int rl_digit_loop1 (); void _rl_vi_initialize_line () { - register int i; + register uint i; for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) vi_mark_chars[i] = -1; @@ -183,7 +183,7 @@ _rl_vi_stuff_insert (count) puts you back into insert mode. */ int rl_vi_redo (count, c) - int count, c; + int count, c __attribute__((unused)); { if (!rl_explicit_arg) { @@ -218,8 +218,8 @@ rl_vi_undo (count, key) /* Yank the nth arg from the previous line into this line at point. */ int -rl_vi_yank_arg (count, key) - int count, key; +rl_vi_yank_arg (count, key) + int count, key __attribute__((unused)); { /* Readline thinks that the first word on a line is the 0th, while vi thinks the first word on a line is the 1st. Compensate. */ @@ -300,7 +300,7 @@ rl_vi_search (count, key) /* Completion, from vi's point of view. */ int rl_vi_complete (ignore, key) - int ignore, key; + int ignore __attribute__((unused)), key; { if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) { @@ -329,7 +329,7 @@ rl_vi_complete (ignore, key) /* Tilde expansion for vi mode. */ int rl_vi_tilde_expand (ignore, key) - int ignore, key; + int ignore __attribute__((unused)), key; { rl_tilde_expand (0, key); _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ @@ -401,7 +401,7 @@ rl_vi_end_word (count, key) /* Move forward a word the way that 'W' does. */ int rl_vi_fWord (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point < (rl_end - 1)) { @@ -418,7 +418,7 @@ rl_vi_fWord (count, ignore) int rl_vi_bWord (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point > 0) { @@ -442,7 +442,7 @@ rl_vi_bWord (count, ignore) int rl_vi_eWord (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point < (rl_end - 1)) { @@ -472,7 +472,7 @@ rl_vi_eWord (count, ignore) int rl_vi_fword (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point < (rl_end - 1)) { @@ -498,7 +498,7 @@ rl_vi_fword (count, ignore) int rl_vi_bword (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point > 0) { @@ -537,7 +537,7 @@ rl_vi_bword (count, ignore) int rl_vi_eword (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { while (count-- && rl_point < rl_end - 1) { @@ -562,7 +562,7 @@ rl_vi_eword (count, ignore) int rl_vi_insert_beg (count, key) - int count, key; + int count __attribute__((unused)), key; { rl_beg_of_line (1, key); rl_vi_insertion_mode (1, key); @@ -571,7 +571,7 @@ rl_vi_insert_beg (count, key) int rl_vi_append_mode (count, key) - int count, key; + int count __attribute__((unused)), key; { if (rl_point < rl_end) rl_point++; @@ -581,7 +581,7 @@ rl_vi_append_mode (count, key) int rl_vi_append_eol (count, key) - int count, key; + int count __attribute__((unused)), key; { rl_end_of_line (1, key); rl_vi_append_mode (1, key); @@ -591,7 +591,7 @@ rl_vi_append_eol (count, key) /* What to do in the case of C-d. */ int rl_vi_eof_maybe (count, c) - int count, c; + int count __attribute__((unused)), c __attribute__((unused)); { return (rl_newline (1, '\n')); } @@ -602,7 +602,7 @@ rl_vi_eof_maybe (count, c) switching keymaps. */ int rl_vi_insertion_mode (count, key) - int count, key; + int count __attribute__((unused)), key; { _rl_keymap = vi_insertion_keymap; _rl_vi_last_key_before_insert = key; @@ -664,7 +664,7 @@ _rl_vi_done_inserting () int rl_vi_movement_mode (count, key) - int count, key; + int count __attribute__((unused)), key; { if (rl_point > 0) rl_backward (1, key); @@ -686,7 +686,7 @@ rl_vi_arg_digit (count, c) int rl_vi_change_case (count, ignore) - int count, ignore; + int count, ignore __attribute__((unused)); { char c = 0; @@ -724,7 +724,7 @@ rl_vi_change_case (count, ignore) int rl_vi_put (count, key) - int count, key; + int count __attribute__((unused)), key; { if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) rl_point++; @@ -881,7 +881,7 @@ rl_digit_loop1 () int rl_vi_delete_to (count, key) - int count, key; + int count __attribute__((unused)), key; { int c; @@ -961,7 +961,7 @@ rl_vi_change_to (count, key) int rl_vi_yank_to (count, key) - int count, key; + int count __attribute__((unused)), key; { int c, save = rl_point; @@ -1014,7 +1014,7 @@ rl_vi_delete (count, key) int rl_vi_back_to_indent (count, key) - int count, key; + int count __attribute__((unused)), key; { rl_beg_of_line (1, key); while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) @@ -1024,7 +1024,7 @@ rl_vi_back_to_indent (count, key) int rl_vi_first_print (count, key) - int count, key; + int count __attribute__((unused)), key; { return (rl_vi_back_to_indent (1, key)); } @@ -1071,7 +1071,7 @@ rl_vi_char_search (count, key) /* Match brackets */ int rl_vi_match (ignore, key) - int ignore, key; + int ignore __attribute__((unused)), key; { int count = 1, brack, pos; @@ -1152,7 +1152,7 @@ rl_vi_bracktype (c) int rl_vi_change_char (count, key) - int count, key; + int count, key __attribute__((unused)); { int c; @@ -1278,7 +1278,7 @@ rl_vi_overstrike_delete (count, key) int rl_vi_replace (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { int i; @@ -1339,7 +1339,7 @@ rl_vi_possible_completions() /* Functions to save and restore marks. */ int rl_vi_set_mark (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { int ch; @@ -1356,7 +1356,7 @@ rl_vi_set_mark (count, key) int rl_vi_goto_mark (count, key) - int count, key; + int count __attribute__((unused)), key __attribute__((unused)); { int ch; diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 45fbe275476..d2cca98ce63 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -44,7 +44,7 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \ mysqlhotcopy.sh \ mysqldumpslow.sh \ mysqld_multi.sh \ - safe_mysqld.sh + mysqld_safe.sh EXTRA_DIST = $(EXTRA_SCRIPTS) \ mysqlaccess.conf \ diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 40c48188346..1848123fd8e 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -117,7 +117,7 @@ rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_ $BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/scripts/mysql_install_db.sh > $BASE/scripts/mysql_install_db $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \@MYSQLD_USER\@ root \@localstatedir\@ /usr/local/mysql/data < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server -$BASE/bin/replace /my/gnu/bin/hostname /bin/hostname -- $BASE/bin/safe_mysqld +$BASE/bin/replace /my/gnu/bin/hostname /bin/hostname -- $BASE/bin/mysqld_safe mv $BASE/support-files/binary-configure $BASE/configure chmod a+x $BASE/bin/* $BASE/scripts/* $BASE/support-files/mysql-* $BASE/configure diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index f7324668bd2..7e232692ba1 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -333,7 +333,7 @@ then if test "$IN_RPM" -eq 0 then echo "You can start the MySQL daemon with:" - echo "cd @prefix@ ; $bindir/safe_mysqld &" + echo "cd @prefix@ ; $bindir/mysqld_safe &" echo echo "You can test the MySQL daemon with the benchmarks in the 'sql-bench' directory:" echo "cd sql-bench ; run-all-tests" diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 1adaa458271..656894f0e37 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -457,12 +457,12 @@ sub example # directory, that you have (just change the socket, -S=...) # See more detailed information from chapter: # '6 The MySQL Access Privilege System' from the MySQL manual. -# 2.pid-file is very important, if you are using safe_mysqld to start mysqld -# (e.g. --mysqld=safe_mysqld) Every mysqld should have it's own pid-file. -# The advantage using safe_mysqld instead of mysqld directly here is, that -# safe_mysqld 'guards' every mysqld process and will restart it, if mysqld +# 2.pid-file is very important, if you are using mysqld_safe to start mysqld +# (e.g. --mysqld=mysqld_safe) Every mysqld should have it's own pid-file. +# The advantage using mysqld_safe instead of mysqld directly here is, that +# mysqld_safe 'guards' every mysqld process and will restart it, if mysqld # process fails due to signal kill -9, or similar. (Like segmentation fault, -# which MySQL should never do, of course ;) Please note that safe_mysqld +# which MySQL should never do, of course ;) Please note that mysqld_safe # script may require that you start it from a certain place. This means that # you may have to CD to a certain directory, before you start the # mysqld_multi. If you have problems starting, please see the script. @@ -497,7 +497,7 @@ sub example # give you extra performance in a threaded system! # [mysqld_multi] -mysqld = @bindir@/safe_mysqld +mysqld = @bindir@/mysqld_safe mysqladmin = @bindir@/mysqladmin user = multi_admin password = multipass @@ -591,9 +591,9 @@ Options: Using: $opt_log --mysqladmin=... mysqladmin binary to be used for a server shutdown. Using: $mysqladmin ---mysqld=... mysqld binary to be used. Note that you can give safe_mysqld +--mysqld=... mysqld binary to be used. Note that you can give mysqld_safe to this option also. The options are passed to mysqld. Just - make sure you have mysqld in your PATH or fix safe_mysqld. + make sure you have mysqld in your PATH or fix mysqld_safe. Using: $mysqld --no-log Print to stdout instead of the log file. By default the log file is turned on. diff --git a/scripts/safe_mysqld-watch.sh b/scripts/mysqld_safe-watch.sh index 30f95fd7a86..c59b3b2614d 100644 --- a/scripts/safe_mysqld-watch.sh +++ b/scripts/mysqld_safe-watch.sh @@ -8,7 +8,7 @@ # binary installation that has other paths than you are using. # # mysql.server works by first doing a cd to the base directory and from there -# executing safe_mysqld +# executing mysqld_safe # Check if we are starting this relative (for the binary release) if test -f ./data/mysql/db.frm -a -f ./share/mysql/english/errmsg.sys -a \ diff --git a/scripts/safe_mysqld.sh b/scripts/mysqld_safe.sh index e7418819604..c6df7400c75 100644 --- a/scripts/safe_mysqld.sh +++ b/scripts/mysqld_safe.sh @@ -8,7 +8,7 @@ # binary installation that has other paths than you are using. # # mysql.server works by first doing a cd to the base directory and from there -# executing safe_mysqld +# executing mysqld_safe trap '' 1 2 3 15 # we shouldn't let anyone kill us @@ -23,32 +23,37 @@ parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on # the command line) into the args variable. - pick_args=$1; shift + pick_args= + if test "$1" = PICK-ARGS-FROM-ARGV + then + pick_args=1 + shift + fi for arg do case "$arg" in # these get passed explicitly to mysqld - --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --pid-file=*) pid_file=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; + --basedir=*) MY_BASEDIR_VERSION=`echo "$arg" | sed -e "s;--basedir=;;"` ;; + --datadir=*) DATADIR=`echo "$arg" | sed -e "s;--datadir=;;"` ;; + --pid-file=*) pid_file=`echo "$arg" | sed -e "s;--pid-file=;;"` ;; --user=*) user=`echo "$arg" | sed -e "s;--[^=]*=;;"` ; SET_USER=1 ;; - # these two might have been set in a [safe_mysqld] section of my.cnf - # they get passed via environment variables to safe_mysqld - --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --port=*) MYSQL_TCP_PORT=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; + # these two might have been set in a [mysqld_safe] section of my.cnf + # they get passed via environment variables to mysqld_safe + --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--socket=;;"` ;; + --port=*) MYSQL_TCP_PORT=`echo "$arg" | sed -e "s;--port=;;"` ;; - # safe_mysqld-specific options - --ledir=*) ledir=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --err-log=*) err_log=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; + # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! + --ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;; + --err-log=*) err_log=`echo "$arg" | sed -e "s;--err-log=;;"` ;; # QQ The --open-files should be removed - --open-files=*) open_files=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --open-files-limit=*) open_files=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --core-file-size=*) core_file_size=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; - --timezone=*) TZ=`echo "$arg" | sed -e "s;--[^=]*=;;"` ; export TZ; ;; - --mysqld=*) MYSQLD=`echo "$arg" | sed -e "s;--[^=]*=;;"` ;; + --open-files=*) open_files=`echo "$arg" | sed -e "s;--open-files=;;"` ;; + --open-files-limit=*) open_files=`echo "$arg" | sed -e "s;--open-files-limit=;;"` ;; + --core-file-size=*) core_file_size=`echo "$arg" | sed -e "s;--core_file_size=;;"` ;; + --timezone=*) TZ=`echo "$arg" | sed -e "s;--timezone=;;"` ; export TZ; ;; + --mysqld=*) MYSQLD=`echo "$arg" | sed -e "s;--mysqld=;;"` ;; --mysqld-version=*) - tmp=`echo "$arg" | sed -e "s;--[^=]*=;;"` + tmp=`echo "$arg" | sed -e "s;--mysqld-version=;;"` if test -n "$tmp" then MYSQLD="mysqld-$tmp" @@ -57,7 +62,7 @@ parse_arguments() { fi ;; *) - if test $pick_args -eq 1 + if test -n "$pick_args" then # This sed command makes sure that any special chars are quoted, # so the arg gets passed exactly to the server. @@ -110,7 +115,7 @@ pid_file= err_log= SET_USER=0 -# Get first arguments from the my.cnf file, groups [mysqld] and [safe_mysqld] +# Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] # and then merge with the command line arguments if test -x ./bin/my_print_defaults then @@ -126,15 +131,15 @@ else fi args= -parse_arguments 0 `$print_defaults $defaults mysqld server safe_mysqld` -parse_arguments 1 "$@" +parse_arguments `$print_defaults $defaults mysqld server mysqld_safe safe_mysqld` +parse_arguments PICK-ARGS-FROM-ARGV "$@" if test ! -x $ledir/$MYSQLD then echo "The file $ledir/$MYSQLD doesn't exist or is not executable" echo "Please do a cd to the mysql installation directory and restart" echo "this script from there as follows:" - echo "./bin/safe_mysqld". + echo "./bin/mysqld_safe". exit 1 fi diff --git a/sql-bench/Makefile.am b/sql-bench/Makefile.am index 80806f35418..e9c3e07beef 100644 --- a/sql-bench/Makefile.am +++ b/sql-bench/Makefile.am @@ -23,14 +23,14 @@ bench_SCRIPTS = test-ATIS test-connect test-create test-insert \ test-big-tables test-select test-wisconsin \ test-alter-table graph-compare-results \ bench-init.pl compare-results run-all-tests \ - server-cfg crash-me copy-db + server-cfg crash-me copy-db bench-count-distinct CLEANFILES = $(bench_SCRIPTS) EXTRA_SCRIPTS = test-ATIS.sh test-connect.sh test-create.sh \ test-insert.sh test-big-tables.sh test-select.sh \ test-alter-table.sh test-wisconsin.sh \ bench-init.pl.sh compare-results.sh server-cfg.sh \ run-all-tests.sh crash-me.sh copy-db.sh \ - graph-compare-results.sh + bench-count-distinct.sh graph-compare-results.sh EXTRA_DIST = $(EXTRA_SCRIPTS) dist-hook: diff --git a/sql-bench/bench-count-distinct.sh b/sql-bench/bench-count-distinct.sh new file mode 100644 index 00000000000..1359a864ac1 --- /dev/null +++ b/sql-bench/bench-count-distinct.sh @@ -0,0 +1,258 @@ +#!@PERL@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA +# +# Test of selecting on keys that consist of many parts +# +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +$opt_loop_count=10000; +$opt_medium_loop_count=200; +$opt_small_loop_count=10; +$opt_regions=6; +$opt_groups=100; + +chomp($pwd = `pwd`); $pwd = "." if ($pwd eq ''); +require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n"; + +$columns=min($limits->{'max_columns'},500,($limits->{'query_size'}-50)/24, + $limits->{'max_conditions'}/2-3); + +if ($opt_small_test) +{ + $opt_loop_count/=10; + $opt_medium_loop_count/=10; + $opt_small_loop_count/=10; + $opt_groups/=10; +} + +print "Testing the speed of selecting on keys that consist of many parts\n"; +print "The test-table has $opt_loop_count rows and the test is done with $columns ranges.\n\n"; + +#### +#### Connect and start timeing +#### + +$dbh = $server->connect(); +$start_time=new Benchmark; + +#### +#### Create needed tables +#### + +goto select_test if ($opt_skip_create); + +print "Creating table\n"; +$dbh->do("drop table bench1" . $server->{'drop_attr'}); + +do_many($dbh,$server->create("bench1", + ["region char(1) NOT NULL", + "idn integer(6) NOT NULL", + "rev_idn integer(6) NOT NULL", + "grp integer(6) NOT NULL"], + ["primary key (region,idn)", + "unique (region,rev_idn)", + "unique (region,grp,idn)"])); +if ($opt_lock_tables) +{ + do_query($dbh,"LOCK TABLES bench1 WRITE"); +} + +if ($opt_fast && defined($server->{vacuum})) +{ + $server->vacuum(1,\$dbh); +} + +#### +#### Insert $opt_loop_count records with +#### region: "A" -> "E" +#### idn: 0 -> count +#### rev_idn: count -> 0, +#### grp: distributed values 0 - > count/100 +#### + +print "Inserting $opt_loop_count rows\n"; + +$loop_time=new Benchmark; +$query="insert into bench1 values ("; +$half_done=$opt_loop_count/2; +for ($id=0,$rev_id=$opt_loop_count-1 ; $id < $opt_loop_count ; $id++,$rev_id--) +{ + $grp=$id*3 % $opt_groups; + $region=chr(65+$id%$opt_regions); + do_query($dbh,"$query'$region',$id,$rev_id,$grp)"); + if ($id == $half_done) + { # Test with different insert + $query="insert into bench1 (region,idn,rev_idn,grp) values ("; + } +} + +$end_time=new Benchmark; +print "Time to insert ($opt_loop_count): " . + timestr(timediff($end_time, $loop_time),"all") . "\n\n"; + +if ($opt_lock_tables) +{ + do_query($dbh,"UNLOCK TABLES"); +} + +if ($opt_fast && defined($server->{vacuum})) +{ + $server->vacuum(0,\$dbh,"bench1"); +} + +if ($opt_lock_tables) +{ + do_query($dbh,"LOCK TABLES bench1 WRITE"); +} + +#### +#### Do some selects on the table +#### + +select_test: + + + +if ($limits->{'group_distinct_functions'}) +{ + print "Testing count(distinct) on the table\n"; + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select count(distinct region) from bench1"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct_key_prefix ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select count(distinct grp) from bench1"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select count(distinct grp),count(distinct rev_idn) from bench1"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct_2 ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select region,count(distinct idn) from bench1 group by region"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct_group_on_key ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select grp,count(distinct idn) from bench1 group by grp"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct_group_on_key_parts ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + for ($i=0 ; $i < $opt_medium_loop_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select grp,count(distinct rev_idn) from bench1 group by grp"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $opt_medium_loop_count)); + } + print_time($estimated); + print " for count_distinct_group ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; + + $loop_time=new Benchmark; + $rows=$estimated=$count=0; + $test_count=$opt_medium_loop_count/10; + for ($i=0 ; $i < $test_count ; $i++) + { + $count++; + $rows+=fetch_all_rows($dbh,"select idn,count(distinct region) from bench1 group by idn"); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$i+1, + $test_count)); + } + print_time($estimated); + print " for count_distinct_big ($count:$rows): " . + timestr(timediff($end_time, $loop_time),"all") . "\n"; +} + +#### +#### End of benchmark +#### + +if ($opt_lock_tables) +{ + do_query($dbh,"UNLOCK TABLES"); +} +if (!$opt_skip_delete) +{ + do_query($dbh,"drop table bench1" . $server->{'drop_attr'}); +} + +if ($opt_fast && defined($server->{vacuum})) +{ + $server->vacuum(0,\$dbh); +} + +$dbh->disconnect; # close connection + +end_benchmark($start_time); diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh index 204d15d7ab3..0c4b1cb1b6a 100644 --- a/sql-bench/bench-init.pl.sh +++ b/sql-bench/bench-init.pl.sh @@ -51,11 +51,12 @@ $log_prog_args=join(" ", skip_arguments(\@ARGV,"comments","cmp","server", "user", "host", "database", "password", "use-old-results","skip-test", "machine", "dir", "suffix", "log")); -GetOptions("skip-test=s","comments=s","cmp=s","server=s","user=s","host=s","database=s","password=s","loop-count=i","row-count=i","skip-create","skip-delete","verbose","fast-insert","lock-tables","debug","fast","force","field-count=i","regions=i","groups=i","time-limit=i","log","use-old-results","machine=s","dir=s","suffix=s","help","odbc","small-test","small-tables","small-key-tables","stage=i","old-headers","die-on-errors","create-options=s","hires","tcpip","silent") || usage(); +GetOptions("skip-test=s","comments=s","cmp=s","server=s","user=s","host=s","database=s","password=s","loop-count=i","row-count=i","skip-create","skip-delete","verbose","fast-insert","lock-tables","debug","fast","force","field-count=i","regions=i","groups=i","time-limit=i","log","use-old-results","machine=s","dir=s","suffix=s","help","odbc","small-test","small-tables","small-key-tables","stage=i","old-headers","die-on-errors","create-options=s","hires","tcpip","silent", +"socket=s") || usage(); usage() if ($opt_help); $server=get_server($opt_server,$opt_host,$opt_database,$opt_odbc, - machine_part()); + machine_part(), $opt_socket); $limits=merge_limits($server,$opt_cmp); $date=date(); @estimated=(0.0,0.0,0.0); # For estimated time support @@ -515,6 +516,10 @@ All benchmarks takes the following options: --password='password' Password for the current user. +--socket='socket' + If the database supports connecting through a Unix socket, + use this socket to connect + --regions This is a test specific option that is only used when debugging a test. This usually means how AND levels should be tested. diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh index a8d992bfdce..8c290a634f7 100644 --- a/sql-bench/server-cfg.sh +++ b/sql-bench/server-cfg.sh @@ -33,10 +33,10 @@ sub get_server { - my ($name,$host,$database,$odbc,$machine)=@_; + my ($name,$host,$database,$odbc,$machine,$socket)=@_; my ($server); if ($name =~ /mysql/i) - { $server=new db_MySQL($host, $database, $machine); } + { $server=new db_MySQL($host, $database, $machine, $socket); } elsif ($name =~ /pg/i) { $server= new db_Pg($host,$database); } elsif ($name =~ /msql/i) @@ -106,13 +106,14 @@ package db_MySQL; sub new { - my ($type,$host,$database,$machine)= @_; + my ($type,$host,$database,$machine,$socket)= @_; my $self= {}; my %limits; bless $self; $self->{'cmp_name'} = "mysql"; - $self->{'data_source'} = "DBI:mysql:$database:$host"; + $self->{'data_source'} = "DBI:mysql:database=$database;host=$host"; + $self->{'data_source'} .= ";mysql_socket=$socket" if($socket); $self->{'limits'} = \%limits; $self->{'smds'} = \%smds; $self->{'blob'} = "blob"; diff --git a/sql/ChangeLog b/sql/ChangeLog index 2289765afad..a75e9761766 100644 --- a/sql/ChangeLog +++ b/sql/ChangeLog @@ -1,3 +1,8 @@ +2000-12-07 Jeremy Cole <jeremy@mysql.com> + +* Added UPDATE ... ORDER BY ... +* Added DELETE ... ORDER BY ... + 2000-11-11 Jeremy Cole <jeremy@mysql.com> * Added ALTER TABLE ... ORDER BY ... diff --git a/sql/Makefile.am b/sql/Makefile.am index f1941e1e25c..3456a07977d 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -24,7 +24,7 @@ INCLUDES = @MT_INCLUDES@ \ @bdb_includes@ @innodb_includes@ @gemini_includes@ \ -I$(srcdir)/../include \ -I$(srcdir)/../regex \ - -I$(srcdir) -I../include -I.. -I. + -I$(srcdir) -I../include -I.. -I. $(openssl_includes) WRAPLIBS= @WRAPLIBS@ SUBDIRS = share libexec_PROGRAMS = mysqld @@ -35,13 +35,16 @@ LDADD = ../isam/libnisam.a \ ../myisam/libmyisam.a \ ../myisammrg/libmyisammrg.a \ ../heap/libheap.a \ + ../vio/libvio.a \ ../mysys/libmysys.a \ ../dbug/libdbug.a \ ../regex/libregex.a \ ../strings/libmystrings.a + mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ - @bdb_libs@ @innodb_libs@ @gemini_libs@ \ - $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ + @bdb_libs@ @innodb_libs@ @pstack_libs@ \ + @gemini_libs@ \ + $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ item_strfunc.h item_timefunc.h item_uniq.h \ item_create.h mysql_priv.h \ @@ -54,18 +57,18 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h md5.h \ log_event.h mini_client.h sql_repl.h slave.h \ - stacktrace.h -mysqld_SOURCES = sql_lex.cc \ + stacktrace.h sql_sort.h +mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ thr_malloc.cc item_create.cc \ field.cc key.cc sql_class.cc sql_list.cc \ - net_serv.cc violite.c net_pkg.cc lock.cc my_lock.c \ + net_serv.cc net_pkg.cc lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ convert.cc sql_parse.cc sql_yacc.yy \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ - sql_update.cc sql_delete.cc \ + sql_update.cc sql_delete.cc uniques.cc \ procedure.cc item_uniq.cc sql_test.cc \ log.cc log_event.cc init.cc derror.cc sql_acl.cc \ unireg.cc \ @@ -77,9 +80,9 @@ mysqld_SOURCES = sql_lex.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ - slave.cc sql_repl.cc \ + slave.cc sql_repl.cc sql_union.cc \ mini_client.cc mini_client_errors.c \ - md5.c stacktrace.c + md5.c stacktrace.c gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) diff --git a/sql/filesort.cc b/sql/filesort.cc index 86c95395965..92886242a4a 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -22,13 +22,11 @@ #include <stddef.h> /* for macro offsetof */ #endif #include <m_ctype.h> +#include "sql_sort.h" + #ifndef THREAD #define SKIPP_DBUG_IN_FILESORT #endif - /* static variabels */ - -#define MERGEBUFF 7 -#define MERGEBUFF2 15 /* How to write record_ref. */ @@ -36,28 +34,6 @@ if (my_b_write((file),(byte*) (from),param->ref_length)) \ DBUG_RETURN(1); -typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */ - my_off_t file_pos; /* Where we are in the sort file */ - uchar *base,*key; /* key pointers */ - ha_rows count; /* Number of rows in table */ - ulong mem_count; /* numbers of keys in memory */ - ulong max_keys; /* Max keys in buffert */ -} BUFFPEK; - - -typedef struct st_sort_param { - uint sort_length; /* Length of sortarg */ - uint keys; /* Max antal nycklar / buffert */ - uint ref_length; /* Length of record ref. */ - ha_rows max_rows,examined_rows; - TABLE *sort_form; /* For quicker make_sortkey */ - SORT_FIELD *local_sortorder; - SORT_FIELD *end; -#ifdef USE_STRCOLL - char* tmp_buffer; -#endif -} SORTPARAM; - /* functions defined in this file */ static char **make_char_array(register uint fields, uint length, myf my_flag); @@ -70,27 +46,26 @@ static int write_keys(SORTPARAM *param,uchar * *sort_keys, IO_CACHE *tempfile); static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos); -static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count); -static int merge_many_buff(SORTPARAM *param,uchar * *sort_keys, - BUFFPEK *buffpek, - uint *maxbuffer, IO_CACHE *t_file); -static uint read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek, - uint sort_length); -static int merge_buffers(SORTPARAM *param,IO_CACHE *from_file, - IO_CACHE *to_file,uchar * *sort_keys, - BUFFPEK *lastbuff,BUFFPEK *Fb, - BUFFPEK *Tb,int flag); -static int merge_index(SORTPARAM *param,uchar * *sort_keys, +static int merge_index(SORTPARAM *param,uchar *sort_buffer, BUFFPEK *buffpek, uint maxbuffer,IO_CACHE *tempfile, IO_CACHE *outfile); +static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count); static uint sortlength(SORT_FIELD *sortorder,uint length); - /* Makes a indexfil of recordnumbers of a sorted database */ - /* outfile is reset before data is written to it, if it wasn't - open a new file is opened */ + /* + Creates a set of pointers that can be used to read the rows + in sorted order. This should be done with the functions + in records.cc + + Before calling filesort, one must have done + table->file->info(HA_STATUS_VARIABLE) -ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length, + The result set is stored in table->io_cache or + table->record_pointers + */ + +ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, SQL_SELECT *select, ha_rows special, ha_rows max_rows, ha_rows *examined_rows) { @@ -102,19 +77,19 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length, IO_CACHE tempfile,*selected_records_file,*outfile; SORTPARAM param; DBUG_ENTER("filesort"); - DBUG_EXECUTE("info",TEST_filesort(table,sortorder,s_length,special);); + DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length,special);); #ifdef SKIPP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif - outfile= table[0]->io_cache; + outfile= table->io_cache; my_b_clear(&tempfile); buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1; maxbuffer=1; - param.ref_length= table[0]->file->ref_length; + bzero((char*) ¶m,sizeof(param)); + param.ref_length= table->file->ref_length; param.sort_length=sortlength(sortorder,s_length)+ param.ref_length; param.max_rows= max_rows; - param.examined_rows=0; if (select && select->quick) { @@ -139,17 +114,14 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length, #ifdef CAN_TRUST_RANGE else if (select && select->quick && select->quick->records > 0L) { - /* Get record-count */ - table[0]->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2), - table[0]->file->records)+EXTRA_RECORDS; + table->file->records)+EXTRA_RECORDS; selected_records_file=0; } #endif else { - table[0]->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);/* Get record-count */ - records=table[0]->file->estimate_number_of_rows(); + records=table->file->estimate_number_of_rows(); selected_records_file= 0; } if (param.sort_length == param.ref_length && records > param.max_rows) @@ -203,7 +175,7 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length, my_error(ER_OUTOFMEMORY,MYF(ME_ERROR+ME_WAITTANG),sortbuff_size); goto err; } - param.sort_form= table[0]; + param.sort_form= table; param.end=(param.local_sortorder=sortorder)+s_length; if ((records=find_all_keys(¶m,select,sort_keys,buffpek,&maxbuffer, &tempfile, selected_records_file)) == @@ -225,12 +197,14 @@ ha_rows filesort(TABLE **table, SORT_FIELD *sortorder, uint s_length, param.keys=((param.keys*(param.sort_length+sizeof(char*))) / param.sort_length-1); - if (merge_many_buff(¶m,sort_keys,buffpek,&maxbuffer,&tempfile)) + if (merge_many_buff(¶m,(uchar*) sort_keys,buffpek,&maxbuffer, + &tempfile)) goto err; if (flush_io_cache(&tempfile) || reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) goto err; - if (merge_index(¶m,sort_keys,buffpek,maxbuffer,&tempfile,outfile)) + if (merge_index(¶m,(uchar*) sort_keys,buffpek,maxbuffer,&tempfile, + outfile)) goto err; } if (records > param.max_rows) @@ -631,8 +605,8 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count) /* Merge buffers to make < MERGEBUFF2 buffers */ -static int merge_many_buff(SORTPARAM *param, uchar **sort_keys, - BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file) +int merge_many_buff(SORTPARAM *param, uchar *sort_buffer, + BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file) { register int i; IO_CACHE t_file2,*from_file,*to_file,*temp; @@ -654,11 +628,11 @@ static int merge_many_buff(SORTPARAM *param, uchar **sort_keys, lastbuff=buffpek; for (i=0 ; i <= (int) *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF) { - if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++, + if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++, buffpek+i,buffpek+i+MERGEBUFF-1,0)) break; /* purecov: inspected */ } - if (merge_buffers(param,from_file,to_file,sort_keys,lastbuff++, + if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++, buffpek+i,buffpek+ *maxbuffer,0)) break; /* purecov: inspected */ if (flush_io_cache(to_file)) @@ -677,8 +651,8 @@ static int merge_many_buff(SORTPARAM *param, uchar **sort_keys, /* Read data to buffer */ /* This returns (uint) -1 if something goes wrong */ -static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, - uint sort_length) +uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, + uint sort_length) { register uint count; uint length; @@ -699,39 +673,44 @@ static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, /* Merge buffers to one buffer */ -static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, - IO_CACHE *to_file, uchar **sort_keys, - BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb, - int flag) +int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, + IO_CACHE *to_file, uchar *sort_buffer, + BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb, + int flag) { int error; uint sort_length,offset; ulong maxcount; - ha_rows count,max_rows; + ha_rows max_rows,org_max_rows; my_off_t to_start_filepos; uchar *strpos; BUFFPEK *buffpek,**refpek; QUEUE queue; + qsort2_cmp cmp; volatile bool *killed= ¤t_thd->killed; + bool not_killable; DBUG_ENTER("merge_buffers"); statistic_increment(filesort_merge_passes, &LOCK_status); + if (param->not_killable) + { + killed= ¬_killable; + not_killable=0; + } - count=error=0; - offset=param->sort_length-param->ref_length; + error=0; + offset=(sort_length=param->sort_length)-param->ref_length; maxcount=(ulong) (param->keys/((uint) (Tb-Fb) +1)); to_start_filepos=my_b_tell(to_file); - strpos=(uchar*) sort_keys; - sort_length=param->sort_length; - max_rows=param->max_rows; + strpos=(uchar*) sort_buffer; + org_max_rows=max_rows=param->max_rows; if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0, (int (*) (void *, byte *,byte*)) - get_ptr_compare(sort_length),(void*) &sort_length)) + (cmp=get_ptr_compare(sort_length)),(void*) &sort_length)) DBUG_RETURN(1); /* purecov: inspected */ for (buffpek= Fb ; buffpek <= Tb ; buffpek++) { - count+= buffpek->count; buffpek->base= strpos; buffpek->max_keys=maxcount; strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek, @@ -741,15 +720,46 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, queue_insert(&queue,(byte*) buffpek); } + if (param->unique_buff) + { + /* + Called by Unique::get() + Copy the first argument to param->unique_buff for unique removal. + Store it also in 'to_file'. + + This is safe as we know that there is always more than one element + in each block to merge (This is guaranteed by the Unique:: algorithm + */ + buffpek=(BUFFPEK*) queue_top(&queue); + memcpy(param->unique_buff, buffpek->key, sort_length); + if (my_b_write(to_file,(byte*) buffpek->key, sort_length)) + { + error=1; goto err; /* purecov: inspected */ + } + buffpek->key+=sort_length; + buffpek->mem_count--; + max_rows--; + queue_replaced(&queue); // Top element has been used + } + else + cmp=0; // Not unique + while (queue.elements > 1) { if (*killed) { - error=1; goto err; /* purecov: inspected */ + error=1; goto err; /* purecov: inspected */ } for (;;) { buffpek=(BUFFPEK*) queue_top(&queue); + if (cmp) // Remove duplicates + { + if (!(*cmp)(&sort_length, &(param->unique_buff), + (uchar**) &buffpek->key)) + goto skip_duplicate; + memcpy(param->unique_buff, (uchar*) buffpek->key,sort_length); + } if (flag == 0) { if (my_b_write(to_file,(byte*) buffpek->key, sort_length)) @@ -766,6 +776,8 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, error=0; /* purecov: inspected */ goto end; /* purecov: inspected */ } + + skip_duplicate: buffpek->key+=sort_length; if (! --buffpek->mem_count) { @@ -798,14 +810,28 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, break; /* One buffer have been removed */ } else if (error == -1) - goto err; /* purecov: inspected */ + goto err; /* purecov: inspected */ } queue_replaced(&queue); /* Top element has been replaced */ } } buffpek=(BUFFPEK*) queue_top(&queue); - buffpek->base=(uchar *) sort_keys; + buffpek->base= sort_buffer; buffpek->max_keys=param->keys; + + /* + As we know all entries in the buffer are unique, we only have to + check if the first one is the same as the last one we wrote + */ + if (cmp) + { + if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key)) + { + buffpek->key+=sort_length; // Remove duplicate + --buffpek->mem_count; + } + } + do { if ((ha_rows) buffpek->mem_count > max_rows) @@ -813,6 +839,7 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, buffpek->mem_count=(uint) max_rows; buffpek->count=0; /* Don't read more */ } + max_rows-=buffpek->mem_count; if (flag == 0) { if (my_b_write(to_file,(byte*) buffpek->key, @@ -837,7 +864,7 @@ static int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, != -1 && error != 0); end: - lastbuff->count=min(count,param->max_rows); + lastbuff->count=min(org_max_rows-max_rows,param->max_rows); lastbuff->file_pos=to_start_filepos; err: delete_queue(&queue); @@ -847,12 +874,12 @@ err: /* Do a merge to output-file (save only positions) */ -static int merge_index(SORTPARAM *param, uchar **sort_keys, +static int merge_index(SORTPARAM *param, uchar *sort_buffer, BUFFPEK *buffpek, uint maxbuffer, IO_CACHE *tempfile, IO_CACHE *outfile) { DBUG_ENTER("merge_index"); - if (merge_buffers(param,tempfile,outfile,sort_keys,buffpek,buffpek, + if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek, buffpek+maxbuffer,1)) DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(0); diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index e05fdafcbc4..36683c0f239 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -472,7 +472,8 @@ int main(int argc,char **argv) int error; MY_INIT(argv[0]); - start_value=6130115L; best_t1=3632784L; best_t2=86437L; best_type=3; /* mode=4229 add=2 type: 0 */ + + start_value=2250933L; best_t1=2721579L; best_t2=4627039L; best_type=3; /* mode=4567 add=4 type: 0 */ if (get_options(argc,(char **) argv)) exit(1); diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 13dccc2bf64..eff69893502 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -247,7 +247,7 @@ THR_LOCK_DATA **ha_heap::store_lock(THD *thd, int ha_heap::delete_table(const char *name) { - int error=heap_delete_all(name); + int error=heap_delete_table(name); return error == ENOENT ? 0 : error; } @@ -272,7 +272,6 @@ ha_rows ha_heap::records_in_range(int inx, return 10; // Good guess } -/* We can just delete the heap on creation */ int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 104aaf8886c..cb76c034749 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -81,13 +81,19 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_buffer_pool_size, innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_lock_wait_timeout; -char *innobase_data_home_dir, *innobase_data_file_path; +char *innobase_data_home_dir; char *innobase_log_group_home_dir, *innobase_log_arch_dir; char *innobase_unix_file_flush_method; bool innobase_flush_log_at_trx_commit, innobase_log_archive, innobase_use_native_aio; -/* innobase_data_file_path=ibdata:15,idata2:1,... */ +/* + Set default InnoDB size to 64M, to let users use InnoDB without having + to specify any startup options. +*/ + +char *innobase_data_file_path= (char*) "ibdata1:64M"; +char *internal_innobase_data_file_path=0; /* The following counter is used to convey information to InnoDB about server activity: in selects it is not sensible to call @@ -214,7 +220,7 @@ innobase_mysql_print_thd( } if (thd->query) { - printf(" %0.100s", thd->query); + printf(" %-.100s", thd->query); } printf("\n"); @@ -299,7 +305,7 @@ innobase_parse_data_file_paths_and_sizes(void) ulint size; ulint i = 0; - str = innobase_data_file_path; + str = internal_innobase_data_file_path; /* First calculate the number of data files and check syntax: path:size[M];path:size[M]... . Note that a Windows path may @@ -375,7 +381,7 @@ innobase_parse_data_file_paths_and_sizes(void) /* Then store the actual values to our arrays */ - str = innobase_data_file_path; + str = internal_innobase_data_file_path; i = 0; while (*str != '\0') { @@ -539,21 +545,9 @@ innobase_init(void) /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ - if (!innobase_data_file_path) - { - fprintf(stderr, - "Cannot initialize InnoDB as 'innodb_data_file_path' is not set.\n" - "If you do not want to use transactional InnoDB tables, add a line\n" - "skip-innodb\n" - "to the [mysqld] section of init parameters in your my.cnf\n" - "or my.ini. If you want to use InnoDB tables, add for example,\n" - "innodb_data_file_path = /mysql/data/ibdata1:20M\n" - "More information on setting the parameters you find in the\n" - "manual.\n"); - - innodb_skip=1; - DBUG_RETURN(FALSE); // Continue without innobase - } + // Make a copy of innobase_data_file_path to not modify the original + internal_innobase_data_file_path=my_strdup(innobase_data_file_path, + MYF(MY_WME)); srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir : current_dir); @@ -623,6 +617,7 @@ innobase_end(void) err = innobase_shutdown_for_mysql(); hash_free(&innobase_open_tables); + my_free(internal_innobase_data_file_path,MYF(MY_ALLOW_ZERO_PTR)); if (err != DB_SUCCESS) { @@ -828,7 +823,7 @@ normalize_table_name( } /********************************************************************* -Creates and opens a handle to a table which already exists in an Innnobase +Creates and opens a handle to a table which already exists in an Innobase database. */ int @@ -1910,7 +1905,7 @@ ha_innobase::change_active_index( build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW); - return(0); + DBUG_RETURN(0); } /************************************************************************** @@ -2699,7 +2694,7 @@ ha_innobase::records_in_range( DBUG_ENTER("records_in_range"); if (prebuilt->trx) { - prebuilt->trx->op_info = "estimating range size"; + prebuilt->trx->op_info = (char*) "estimating range size"; } active_index = keynr; @@ -2735,7 +2730,7 @@ ha_innobase::records_in_range( my_free((char*) key_val_buff2, MYF(0)); if (prebuilt->trx) { - prebuilt->trx->op_info = ""; + prebuilt->trx->op_info = (char*) ""; } DBUG_RETURN((ha_rows) n_rows); @@ -2759,7 +2754,7 @@ ha_innobase::estimate_number_of_rows(void) if (prebuilt->trx) { prebuilt->trx->op_info = - "estimating upper bound of table size"; + (char*) "estimating upper bound of table size"; } DBUG_ENTER("info"); @@ -2775,7 +2770,7 @@ ha_innobase::estimate_number_of_rows(void) /* The minimum clustered index record size is 20 bytes */ if (prebuilt->trx) { - prebuilt->trx->op_info = ""; + prebuilt->trx->op_info = (char*) ""; } return((ha_rows) (1000 + data_file_length / 20)); @@ -2817,7 +2812,7 @@ ha_innobase::info( DBUG_ENTER("info"); if (prebuilt->trx) { - prebuilt->trx->op_info = "calculating table stats"; + prebuilt->trx->op_info = (char*) "calculating table stats"; } ib_table = prebuilt->table; @@ -2883,7 +2878,7 @@ ha_innobase::info( } if (prebuilt->trx) { - prebuilt->trx->op_info = ""; + prebuilt->trx->op_info = (char*) ""; } DBUG_VOID_RETURN; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index a429d5308dd..c192443da0a 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -535,8 +535,8 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) int error=0; uint extra_testflag=0; bool optimize_done= !optimize, statistics_done=0; - char fixed_name[FN_REFLEN]; const char *old_proc_info=thd->proc_info; + char fixed_name[FN_REFLEN]; MYISAM_SHARE* share = file->s; ha_rows rows= file->state->records; DBUG_ENTER("ha_myisam::repair"); @@ -548,8 +548,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) param.thd=thd; param.tmpdir=mysql_tmpdir; param.out_flag=0; - VOID(fn_format(fixed_name,file->filename,"",MI_NAME_IEXT, - 4+ (param.opt_follow_links ? 16 : 0))); + strmov(fixed_name,file->filename); // Don't lock tables if we have used LOCK TABLE if (!thd->locked_tables && mi_lock_database(file,F_WRLCK)) @@ -645,8 +644,21 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) void ha_myisam::deactivate_non_unique_index(ha_rows rows) { - if (!(specialflag & SPECIAL_SAFE_MODE)) - mi_disable_non_unique_index(file,rows); + MYISAM_SHARE* share = file->s; + if (share->state.key_map == ((ulonglong) 1L << share->base.keys)-1) + { + if (!(specialflag & SPECIAL_SAFE_MODE)) + if (rows==HA_POS_ERROR) + mi_extra(file, HA_EXTRA_NO_KEYS); + else + { + mi_disable_non_unique_index(file,rows); + mi_extra(file, HA_EXTRA_BULK_INSERT_BEGIN); + } + enable_activate_all_index=1; + } + else + enable_activate_all_index=0; } @@ -656,7 +668,10 @@ bool ha_myisam::activate_all_index(THD *thd) MI_CHECK param; MYISAM_SHARE* share = file->s; DBUG_ENTER("activate_all_index"); - if (share->state.key_map != ((ulonglong) 1L << share->base.keys)-1) + + mi_extra(file, HA_EXTRA_BULK_INSERT_END); + if (enable_activate_all_index && + share->state.key_map != ((ulonglong) 1L << share->base.keys)-1) { const char *save_proc_info=thd->proc_info; thd->proc_info="Creating index"; @@ -671,6 +686,8 @@ bool ha_myisam::activate_all_index(THD *thd) error=repair(thd,param,0) != HA_ADMIN_OK; thd->proc_info=save_proc_info; } + else + enable_activate_all_index=1; DBUG_RETURN(error); } @@ -821,6 +838,8 @@ void ha_myisam::position(const byte* record) void ha_myisam::info(uint flag) { MI_ISAMINFO info; + char name_buff[FN_REFLEN]; + (void) mi_status(file,&info,flag); if (flag & HA_STATUS_VARIABLE) { @@ -850,6 +869,18 @@ void ha_myisam::info(uint flag) raid_type=info.raid_type; raid_chunks=info.raid_chunks; raid_chunksize=info.raid_chunksize; + + /* + Set data_file_name and index_file_name to point at the symlink value + if table is symlinked (Ie; Real name is not same as generated name) + */ + data_file_name=index_file_name=0; + fn_format(name_buff, file->filename, "", MI_NAME_DEXT, 2); + if (strcmp(name_buff, info.data_file_name)) + data_file_name=info.data_file_name; + strmov(fn_ext(name_buff),MI_NAME_IEXT); + if (strcmp(name_buff, info.index_file_name)) + index_file_name=info.index_file_name; } if (flag & HA_STATUS_ERRKEY) { @@ -867,7 +898,8 @@ int ha_myisam::extra(enum ha_extra_function operation) { if (((specialflag & SPECIAL_SAFE_MODE) || (test_flags & TEST_NO_EXTRA)) && (operation == HA_EXTRA_WRITE_CACHE || - operation == HA_EXTRA_KEYREAD)) + operation == HA_EXTRA_KEYREAD || + operation == HA_EXTRA_BULK_INSERT_BEGIN)) return 0; return mi_extra(file,operation); } @@ -905,6 +937,7 @@ THR_LOCK_DATA **ha_myisam::store_lock(THD *thd, void ha_myisam::update_create_info(HA_CREATE_INFO *create_info) { + MI_ISAMINFO info; table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST); if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) { @@ -916,6 +949,8 @@ void ha_myisam::update_create_info(HA_CREATE_INFO *create_info) create_info->raid_chunks= raid_chunks; create_info->raid_chunksize= raid_chunksize; } + create_info->data_file_name=data_file_name; + create_info->index_file_name=index_file_name; } @@ -1087,8 +1122,10 @@ int ha_myisam::create(const char *name, register TABLE *form, create_info.raid_type=info->raid_type; create_info.raid_chunks=info->raid_chunks ? info->raid_chunks : RAID_DEFAULT_CHUNKS; create_info.raid_chunksize=info->raid_chunksize ? info->raid_chunksize : RAID_DEFAULT_CHUNKSIZE; + create_info.data_file_name= info->data_file_name; + create_info.index_file_name=info->index_file_name; - error=mi_create(fn_format(buff,name,"","",2+4+16), + error=mi_create(fn_format(buff,name,"","",2+4), form->keys,keydef, (uint) (recinfo_pos-recinfo), recinfo, 0, (MI_UNIQUEDEF*) 0, diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 6451e2b80ee..d870331e750 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -38,6 +38,8 @@ class ha_myisam: public handler { MI_INFO *file; uint int_option_flag; + char *data_file_name, *index_file_name; + bool enable_activate_all_index; int repair(THD *thd, MI_CHECK ¶m, bool optimize); public: @@ -46,7 +48,8 @@ class ha_myisam: public handler HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER | HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY | HA_LONGLONG_KEYS | HA_NULL_KEY | - HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY) + HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY), + enable_activate_all_index(1) {} ~ha_myisam() {} const char *table_type() const { return "MyISAM"; } diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 1feaa4e5d66..abcf81806ad 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -227,7 +227,7 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info) for (table=file->open_tables ; table != file->end_table ; table++) { - char *name=table->table->s->filename; + char *name=table->table->filename; char buff[FN_REFLEN]; TABLE_LIST *ptr; if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) @@ -274,7 +274,7 @@ void ha_myisammrg::append_create_info(String *packet) for (first=table=file->open_tables ; table != file->end_table ; table++) { - char *name=table->table->s->filename; + char *name=table->table->filename; fn_format(buff,name,"","",3); if (table != first) packet->append(','); diff --git a/sql/handler.cc b/sql/handler.cc index 1c50634de1f..f790417cf79 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -78,7 +78,7 @@ enum db_type ha_checktype(enum db_type database_type) return(berkeley_skip ? DB_TYPE_MYISAM : database_type); #endif #ifdef HAVE_INNOBASE_DB - case DB_TYPE_INNOBASE: + case DB_TYPE_INNODB: return(innodb_skip ? DB_TYPE_MYISAM : database_type); #endif #ifdef HAVE_GEMINI_DB @@ -124,7 +124,7 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) return new ha_berkeley(table); #endif #ifdef HAVE_INNOBASE_DB - case DB_TYPE_INNOBASE: + case DB_TYPE_INNODB: return new ha_innobase(table); #endif #ifdef HAVE_GEMINI_DB @@ -803,8 +803,10 @@ int handler::index_next_same(byte *buf, const byte *key, uint keylen) /* - The following is only needed if we would like to use the database - for internal temporary tables + This is called to delete all rows in a table + If the handler don't support this, then this function will + return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one + by one. */ int handler::delete_all_rows() @@ -862,5 +864,5 @@ static int NEAR_F delete_file(const char *name,const char *ext,int extflag) { char buff[FN_REFLEN]; VOID(fn_format(buff,name,"",ext,extflag | 4)); - return(my_delete(buff,MYF(MY_WME))); + return(my_delete_with_symlink(buff,MYF(MY_WME))); } diff --git a/sql/handler.h b/sql/handler.h index 4ce743a5edd..4b047fb320e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -111,7 +111,7 @@ enum db_type { DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1, DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM, DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM, DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM, - DB_TYPE_BERKELEY_DB, DB_TYPE_INNOBASE, DB_TYPE_GEMINI, + DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB, DB_TYPE_GEMINI, DB_TYPE_DEFAULT }; enum row_type { ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, ROW_TYPE_DYNAMIC, @@ -143,6 +143,7 @@ typedef struct st_ha_create_information ulonglong max_rows,min_rows; ulonglong auto_increment_value; char *comment,*password; + char *data_file_name, *index_file_name; uint options; /* OR of HA_CREATE_ options */ uint raid_type,raid_chunks; ulong raid_chunksize; @@ -338,6 +339,8 @@ extern TYPELIB ha_table_typelib, tx_isolation_typelib; #define ha_commit(thd) (ha_commit_trans((thd), &((thd)->transaction.all))) #define ha_rollback(thd) (ha_rollback_trans((thd), &((thd)->transaction.all))) +#define ha_supports_generate(T) (T != DB_TYPE_INNODB) + handler *get_new_handler(TABLE *table, enum db_type db_type); my_off_t ha_get_ptr(byte *ptr, uint pack_length); void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos); diff --git a/sql/item.cc b/sql/item.cc index b268c5eb928..c0cdac51b1e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -561,7 +561,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables) { if (!ref) { - if (!(ref=find_item_in_list(this,thd->lex.item_list))) + if (!(ref=find_item_in_list(this,thd->lex.select->item_list))) return 1; max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; @@ -677,5 +677,6 @@ bool field_is_equal_to_item(Field *field,Item *item) #ifdef __GNUC__ template class List<Item>; template class List_iterator<Item>; +template class List_iterator_fast<Item>; template class List<List_item>; #endif diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 373aede7b6b..db1d6911119 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -254,7 +254,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value=stringcmp(a,b); + int value= binary ? stringcmp(a,b) : sortcmp(a,b); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -1129,7 +1129,7 @@ void Item_cond::update_used_tables() { used_tables_cache=0; const_item_cache=1; - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) { @@ -1143,7 +1143,7 @@ void Item_cond::update_used_tables() void Item_cond::print(String *str) { str->append('('); - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; if ((item=li++)) item->print(str); @@ -1160,7 +1160,7 @@ void Item_cond::print(String *str) longlong Item_cond_and::val_int() { - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) { @@ -1179,7 +1179,7 @@ longlong Item_cond_and::val_int() longlong Item_cond_or::val_int() { - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; null_value=0; while ((item=li++)) diff --git a/sql/item_create.cc b/sql/item_create.cc index ef9f5f2d38b..55f8bb140a9 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -129,6 +129,11 @@ Item *create_func_floor(Item* a) return new Item_func_floor(a); } +Item *create_func_found_rows(void) +{ + return new Item_int("FOUND_ROWS()",(longlong) current_thd->found_rows(),21); +} + Item *create_func_from_days(Item* a) { return new Item_func_from_days(a); diff --git a/sql/item_create.h b/sql/item_create.h index cc7497b0183..54d2ff035ea 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -37,6 +37,7 @@ Item *create_func_degrees(Item *); Item *create_func_exp(Item* a); Item *create_func_find_in_set(Item* a, Item *b); Item *create_func_floor(Item* a); +Item *create_func_found_rows(void); Item *create_func_from_days(Item* a); Item *create_func_get_lock(Item* a, Item *b); Item *create_func_hex(Item *a); diff --git a/sql/item_func.cc b/sql/item_func.cc index 56e3d562ee8..3ef5ed5d7a3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -43,7 +43,7 @@ Item_func::Item_func(List<Item> &list) if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) { uint i=0; - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) @@ -2027,7 +2027,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) bool Item_func_match::fix_index() { - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Item_field *item; uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index bd7fde79629..12561fe4326 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -30,7 +30,6 @@ #ifdef HAVE_CRYPT_H #include <crypt.h> #endif - #include "md5.h" String empty_string(""); @@ -66,13 +65,13 @@ String *Item_func_md5::val_str(String *str) String * sptr= args[0]->val_str(str); if (sptr) { - MD5_CTX context; + my_MD5_CTX context; unsigned char digest[16]; null_value=0; - MD5Init (&context); - MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); - MD5Final (digest, &context); + my_MD5Init (&context); + my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); + my_MD5Final (digest, &context); str->alloc(32); // Ensure that memory is free sprintf((char *) str->ptr(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5b24a1eda90..a7e608855ee 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -30,7 +30,7 @@ Item_sum::Item_sum(List<Item> &list) if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) { uint i=0; - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) @@ -788,11 +788,74 @@ String *Item_std_field::val_str(String *str) #include "sql_select.h" +static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2) +{ + return memcmp(key1, key2, *(uint*) arg); +} + +static int simple_str_key_cmp(void* arg, byte* key1, byte* key2) +{ + return my_sortcmp(key1, key2, *(uint*) arg); +} + +/* + Did not make this one static - at least gcc gets confused when + I try to declare a static function as a friend. If you can figure + out the syntax to make a static function a friend, make this one + static +*/ + +int composite_key_cmp(void* arg, byte* key1, byte* key2) +{ + Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg; + Field **field = item->table->field; + Field **field_end= field + item->table->fields; + uint32 *lengths=item->field_lengths; + for (; field < field_end; ++field) + { + Field* f = *field; + int len = *lengths++; + int res = f->key_cmp(key1, key2); + if (res) + return res; + key1 += len; + key2 += len; + } + return 0; +} + +/* + helper function for walking the tree when we dump it to MyISAM - + tree_walk will call it for each leaf +*/ + +int dump_leaf(byte* key, uint32 count __attribute__((unused)), + Item_sum_count_distinct* item) +{ + char* buf = item->table->record[0]; + int error; + /* + The first item->rec_offset bytes are taken care of with + restore_record(table,2) in setup() + */ + memcpy(buf + item->rec_offset, key, item->tree.size_of_element); + if ((error = item->table->file->write_row(buf))) + { + if (error != HA_ERR_FOUND_DUPP_KEY && + error != HA_ERR_FOUND_DUPP_UNIQUE) + return 1; + } + return 0; +} + + Item_sum_count_distinct::~Item_sum_count_distinct() { if (table) free_tmp_table(current_thd, table); delete tmp_table_param; + if (use_tree) + delete_tree(&tree); } @@ -829,22 +892,125 @@ bool Item_sum_count_distinct::setup(THD *thd) tmp_table_param->cleanup(); } if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, 0, current_lex->options | thd->options))) + 0, 0, + current_lex->select->options | thd->options))) return 1; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows + table->no_rows=1; + + + // no blobs, otherwise it would be MyISAM + if (table->db_type == DB_TYPE_HEAP) + { + qsort_cmp2 compare_key; + void* cmp_arg; + + // to make things easier for dump_leaf if we ever have to dump to MyISAM + restore_record(table,2); + + if (table->fields == 1) + { + /* + If we have only one field, which is the most common use of + count(distinct), it is much faster to use a simpler key + compare method that can take advantage of not having to worry + about other fields + */ + Field* field = table->field[0]; + switch(field->type()) + { + /* + If we have a string, we must take care of charsets and case + sensitivity + */ + case FIELD_TYPE_STRING: + case FIELD_TYPE_VAR_STRING: + compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp: + simple_str_key_cmp); + break; + default: + /* + Since at this point we cannot have blobs anything else can + be compared with memcmp + */ + compare_key = (qsort_cmp2)simple_raw_key_cmp; + break; + } + key_length = field->pack_length(); + cmp_arg = (void*) &key_length; + rec_offset = 1; + } + else // too bad, cannot cheat - there is more than one field + { + bool all_binary = 1; + Field** field, **field_end; + field_end = (field = table->field) + table->fields; + uint32 *lengths; + if (!(field_lengths= + (uint32*) thd->alloc(sizeof(uint32) * table->fields))) + return 1; + + for (key_length = 0, lengths=field_lengths; field < field_end; ++field) + { + uint32 length= (*field)->pack_length(); + key_length += length; + *lengths++ = length; + if (!(*field)->binary()) + all_binary = 0; // Can't break loop here + } + rec_offset = table->reclength - key_length; + if (all_binary) + { + compare_key = (qsort_cmp2)simple_raw_key_cmp; + cmp_arg = (void*) &key_length; + } + else + { + compare_key = (qsort_cmp2) composite_key_cmp ; + cmp_arg = (void*) this; + } + } + + init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0, + key_length, compare_key, 0, NULL, cmp_arg); + use_tree = 1; + + /* + The only time key_length could be 0 is if someone does + count(distinct) on a char(0) field - stupid thing to do, + but this has to be handled - otherwise someone can crash + the server with a DoS attack + */ + max_elements_in_tree = ((key_length) ? max_heap_table_size/key_length : + 1); + } return 0; } +int Item_sum_count_distinct::tree_to_myisam() +{ + if (create_myisam_from_heap(table, tmp_table_param, + HA_ERR_RECORD_FILE_FULL, 1) || + tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this, + left_root_right)) + return 1; + delete_tree(&tree); + use_tree = 0; + return 0; +} + void Item_sum_count_distinct::reset() { - if (table) + if (use_tree) + reset_tree(&tree); + else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); table->file->delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); - (void) add(); } + (void) add(); } bool Item_sum_count_distinct::add() @@ -859,7 +1025,21 @@ bool Item_sum_count_distinct::add() if ((*field)->is_real_null(0)) return 0; // Don't count NULL - if ((error=table->file->write_row(table->record[0]))) + if (use_tree) + { + /* + If the tree got too big, convert to MyISAM, otherwise insert into the + tree. + */ + if (tree.elements_in_tree > max_elements_in_tree) + { + if(tree_to_myisam()) + return 1; + } + else if (!tree_insert(&tree, table->record[0] + rec_offset, 0)) + return 1; + } + else if ((error=table->file->write_row(table->record[0]))) { if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE) @@ -875,6 +1055,8 @@ longlong Item_sum_count_distinct::val_int() { if (!table) // Empty query return LL(0); + if (use_tree) + return tree.elements_in_tree; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); return table->file->records; } diff --git a/sql/item_sum.h b/sql/item_sum.h index f68dfee1b61..7356eeda28c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -21,6 +21,8 @@ #pragma interface /* gcc class implementation */ #endif +#include <my_tree.h> + class Item_sum :public Item_result_field { public: @@ -144,13 +146,36 @@ class Item_sum_count_distinct :public Item_sum_int TABLE *table; table_map used_table_cache; bool fix_fields(THD *thd,TABLE_LIST *tables); + uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; - bool always_null; + TREE tree; + uint key_length; + + // calculated based on max_heap_table_size. If reached, + // walk the tree and dump it into MyISAM table + uint max_elements_in_tree; + + // the first few bytes of record ( at least one) + // are just markers for deleted and NULLs. We want to skip them since + // they will just bloat the tree without providing any valuable info + int rec_offset; + + // If there are no blobs, we can use a tree, which + // is faster than heap table. In that case, we still use the table + // to help get things set up, but we insert nothing in it + bool use_tree; + bool always_null; // Set to 1 if the result is always NULL + + int tree_to_myisam(); + + friend int composite_key_cmp(void* arg, byte* key1, byte* key2); + friend int dump_leaf(byte* key, uint32 count __attribute__((unused)), + Item_sum_count_distinct* item); public: Item_sum_count_distinct(List<Item> &list) :Item_sum_int(list),table(0),used_table_cache(~(table_map) 0), - tmp_table_param(0),always_null(0) + tmp_table_param(0),use_tree(0),always_null(0) { quick_group=0; } ~Item_sum_count_distinct(); table_map used_tables() const { return used_table_cache; } diff --git a/sql/key.cc b/sql/key.cc index 80a33bc45d3..2c7c9361eb3 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -250,7 +250,7 @@ void key_unpack(String *to,TABLE *table,uint idx) bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) { - List_iterator<Item> f(fields); + List_iterator_fast<Item> f(fields); KEY_PART_INFO *key_part,*key_part_end; for (key_part=table->key_info[idx].key_part,key_part_end=key_part+ table->key_info[idx].key_parts ; diff --git a/sql/lex.h b/sql/lex.h index ed97eea751f..1d481aa7c85 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -70,6 +70,7 @@ static SYMBOL symbols[] = { { "BIGINT", SYM(BIGINT),0,0}, { "BIT", SYM(BIT_SYM),0,0}, { "BINARY", SYM(BINARY),0,0}, + { "BINLOG", SYM(BINLOG_SYM),0,0}, { "BLOB", SYM(BLOB_SYM),0,0}, { "BOOL", SYM(BOOL_SYM),0,0}, { "BOTH", SYM(BOTH),0,0}, @@ -82,6 +83,7 @@ static SYMBOL symbols[] = { { "CHANGED", SYM(CHANGED),0,0}, { "CHECK", SYM(CHECK_SYM),0,0}, { "CHECKSUM", SYM(CHECKSUM_SYM),0,0}, + { "CLOSE", SYM(CLOSE_SYM),0,0}, { "COLUMN", SYM(COLUMN_SYM),0,0}, { "COLUMNS", SYM(COLUMNS),0,0}, { "COMMENT", SYM(COMMENT_SYM),0,0}, @@ -112,6 +114,8 @@ static SYMBOL symbols[] = { { "DELETE", SYM(DELETE_SYM),0,0}, { "DESC", SYM(DESC),0,0}, { "DESCRIBE", SYM(DESCRIBE),0,0}, + { "DIRECTORY", SYM(DIRECTORY_SYM),0,0}, + { "DISABLE", SYM(DISABLE_SYM),0,0}, { "DISTINCT", SYM(DISTINCT),0,0}, { "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */ { "DOUBLE", SYM(DOUBLE_SYM),0,0}, @@ -122,8 +126,10 @@ static SYMBOL symbols[] = { { "ELSE", SYM(ELSE),0,0}, { "ESCAPE", SYM(ESCAPE_SYM),0,0}, { "ESCAPED", SYM(ESCAPED),0,0}, + { "ENABLE", SYM(ENABLE_SYM),0,0}, { "ENCLOSED", SYM(ENCLOSED),0,0}, { "ENUM", SYM(ENUM),0,0}, + { "EVENTS", SYM(EVENTS_SYM),0,0}, { "EXPLAIN", SYM(DESCRIBE),0,0}, { "EXISTS", SYM(EXISTS),0,0}, { "EXTENDED", SYM(EXTENDED_SYM),0,0}, @@ -153,6 +159,7 @@ static SYMBOL symbols[] = { { "GRANTS", SYM(GRANTS),0,0}, { "GROUP", SYM(GROUP),0,0}, { "HAVING", SYM(HAVING),0,0}, + { "HANDLER", SYM(HANDLER_SYM),0,0}, { "HEAP", SYM(HEAP_SYM),0,0}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0}, { "HOUR", SYM(HOUR_SYM),0,0}, @@ -163,6 +170,7 @@ static SYMBOL symbols[] = { { "IGNORE", SYM(IGNORE_SYM),0,0}, { "IN", SYM(IN_SYM),0,0}, { "INDEX", SYM(INDEX),0,0}, + { "INDEXES", SYM(INDEXES),0,0}, { "INFILE", SYM(INFILE),0,0}, { "INNER", SYM(INNER_SYM),0,0}, { "INNOBASE", SYM(INNOBASE_SYM),0,0}, @@ -186,6 +194,7 @@ static SYMBOL symbols[] = { { "KEY", SYM(KEY_SYM),0,0}, { "KEYS", SYM(KEYS),0,0}, { "KILL", SYM(KILL_SYM),0,0}, + { "LAST", SYM(LAST_SYM),0,0}, { "LAST_INSERT_ID", SYM(LAST_INSERT_ID),0,0}, { "LEADING", SYM(LEADING),0,0}, { "LEFT", SYM(LEFT),0,0}, @@ -207,8 +216,10 @@ static SYMBOL symbols[] = { { "MASTER_HOST", SYM(MASTER_HOST_SYM),0,0}, { "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM),0,0}, { "MASTER_LOG_POS", SYM(MASTER_LOG_POS_SYM),0,0}, + { "MASTER_LOG_SEQ", SYM(MASTER_LOG_SEQ_SYM),0,0}, { "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0}, { "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0}, + { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0}, { "MASTER_USER", SYM(MASTER_USER_SYM),0,0}, { "MAX_ROWS", SYM(MAX_ROWS),0,0}, { "MATCH", SYM(MATCH),0,0}, @@ -228,11 +239,13 @@ static SYMBOL symbols[] = { { "MYISAM", SYM(MYISAM_SYM),0,0}, { "NATURAL", SYM(NATURAL),0,0}, { "NATIONAL", SYM(NATIONAL_SYM),0,0}, + { "NEXT", SYM(NEXT_SYM),0,0}, + { "NEW", SYM(NEW_SYM),0,0}, { "NCHAR", SYM(NCHAR_SYM),0,0}, - { "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "NO", SYM(NO_SYM),0,0}, { "NOT", SYM(NOT),0,0}, { "NULL", SYM(NULL_SYM),0,0}, + { "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "ON", SYM(ON),0,0}, { "OPEN", SYM(OPEN_SYM),0,0}, { "OPTIMIZE", SYM(OPTIMIZE),0,0}, @@ -247,6 +260,7 @@ static SYMBOL symbols[] = { { "PASSWORD", SYM(PASSWORD),0,0}, { "PURGE", SYM(PURGE),0,0}, { "PRECISION", SYM(PRECISION),0,0}, + { "PREV", SYM(PREV_SYM),0,0}, { "PRIMARY", SYM(PRIMARY_SYM),0,0}, { "PROCEDURE", SYM(PROCEDURE),0,0}, { "PROCESS" , SYM(PROCESS),0,0}, @@ -289,6 +303,7 @@ static SYMBOL symbols[] = { { "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0}, { "SQL_BIG_TABLES", SYM(SQL_BIG_TABLES),0,0}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, + { "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0}, { "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0}, { "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0}, { "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0}, @@ -394,6 +409,7 @@ static SYMBOL sql_functions[] = { { "FIND_IN_SET", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_find_in_set)}, { "FLOOR", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_floor)}, { "FORMAT", SYM(FORMAT_SYM),0,0}, + { "FOUND_ROWS", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_found_rows)}, { "FROM_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_from_days)}, { "FROM_UNIXTIME", SYM(FROM_UNIXTIME),0,0}, { "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)}, diff --git a/sql/lock.cc b/sql/lock.cc index aa06822e03f..d9bc5d43c79 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -55,33 +55,13 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) Someone has issued LOCK ALL TABLES FOR READ and we want a write lock Wait until the lock is gone */ - if (thd->global_read_lock) // This thread had the read locks + if (wait_if_global_read_lock(thd, 1)) { - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0), - write_lock_used->table_name); my_free((gptr) sql_lock,MYF(0)); sql_lock=0; break; } - - pthread_mutex_lock(&LOCK_open); - thd->mysys_var->current_mutex= &LOCK_open; - thd->mysys_var->current_cond= &COND_refresh; - thd->proc_info="Waiting for table"; - - while (global_read_lock && ! thd->killed && - thd->version == refresh_version) - { - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - } - pthread_mutex_unlock(&LOCK_open); - pthread_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - thd->proc_info= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - - if (thd->version != refresh_version || thd->killed) + if (thd->version != refresh_version) { my_free((gptr) sql_lock,MYF(0)); goto retry; @@ -394,6 +374,36 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, *****************************************************************************/ /* + Lock and wait for the named lock. + Returns 0 on ok +*/ + +int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list) +{ + int lock_retcode; + int error= -1; + DBUG_ENTER("lock_and_wait_for_table_name"); + + if (wait_if_global_read_lock(thd,0)) + DBUG_RETURN(1); + VOID(pthread_mutex_lock(&LOCK_open)); + if ((lock_retcode = lock_table_name(thd, table_list)) < 0) + goto end; + if (lock_retcode && wait_for_locked_table_names(thd, table_list)) + { + unlock_table_name(thd, table_list); + goto end; + } + error=0; + +end: + pthread_mutex_unlock(&LOCK_open); + start_waiting_global_read_lock(thd); + DBUG_RETURN(error); +} + + +/* Put a not open table with an old refresh version in the table cache. This will force any other threads that uses the table to release it as soon as possible. @@ -404,7 +414,6 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, > 0 table locked, but someone is using it */ - int lock_table_name(THD *thd, TABLE_LIST *table_list) { TABLE *table; @@ -503,3 +512,101 @@ static void print_lock_error(int error) DBUG_VOID_RETURN; } + +/**************************************************************************** + Handling of global read locks + + The global locks are handled through the global variables: + global_read_lock + waiting_for_read_lock + protect_against_global_read_lock +****************************************************************************/ + +volatile uint global_read_lock=0; +static volatile uint protect_against_global_read_lock=0; +static volatile uint waiting_for_read_lock=0; + +bool lock_global_read_lock(THD *thd) +{ + DBUG_ENTER("lock_global_read_lock"); + + if (!thd->global_read_lock) + { + (void) pthread_mutex_lock(&LOCK_open); + const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, + "Waiting to get readlock"); + DBUG_PRINT("info", + ("waiting_for: %d protect_against: %d", + waiting_for_read_lock, protect_against_global_read_lock)); + + waiting_for_read_lock++; + while (protect_against_global_read_lock && !thd->killed) + pthread_cond_wait(&COND_refresh, &LOCK_open); + waiting_for_read_lock--; + if (thd->killed) + { + (void) pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(1); + } + thd->global_read_lock=1; + global_read_lock++; + (void) pthread_mutex_unlock(&LOCK_open); + } + DBUG_RETURN(0); +} + +void unlock_global_read_lock(THD *thd) +{ + uint tmp; + thd->global_read_lock=0; + pthread_mutex_lock(&LOCK_open); + tmp= --global_read_lock; + pthread_mutex_unlock(&LOCK_open); + /* Send the signal outside the mutex to avoid a context switch */ + if (!tmp) + pthread_cond_broadcast(&COND_refresh); +} + + +bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh) +{ + const char *old_message; + bool result=0; + DBUG_ENTER("wait_if_global_read_lock"); + + (void) pthread_mutex_lock(&LOCK_open); + if (global_read_lock) + { + if (thd->global_read_lock) // This thread had the read locks + { + my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); + (void) pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(1); + } + old_message=thd->enter_cond(&COND_refresh, &LOCK_open, + "Waiting for release of readlock"); + while (global_read_lock && ! thd->killed && + (!abort_on_refresh || thd->version == refresh_version)) + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + if (thd->killed) + result=1; + thd->exit_cond(old_message); + } + if (!abort_on_refresh && !result) + protect_against_global_read_lock++; + pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(result); +} + + +void start_waiting_global_read_lock(THD *thd) +{ + bool tmp; + DBUG_ENTER("start_waiting_global_read_lock"); + (void) pthread_mutex_lock(&LOCK_open); + tmp= (!--protect_against_global_read_lock && waiting_for_read_lock); + (void) pthread_mutex_unlock(&LOCK_open); + if (tmp) + pthread_cond_broadcast(&COND_refresh); + DBUG_VOID_RETURN; +} diff --git a/sql/log.cc b/sql/log.cc index d7825ce0e93..51bf077895a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -81,7 +81,7 @@ static int find_uniq_filename(char *name) MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1), name(0), log_type(LOG_CLOSED),write_error(0), - inited(0), no_rotate(0) + inited(0), log_seq(1), file_id(1),no_rotate(0) { /* We don't want to intialize LOCK_Log here as the thread system may @@ -230,8 +230,11 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) || open_index(O_APPEND | O_RDWR | O_CREAT)) goto err; + + log_seq = 1; Start_log_event s; bool error; + s.set_log_seq(0, this); s.write(&log_file); flush_io_cache(&log_file); pthread_mutex_lock(&LOCK_index); @@ -532,7 +535,15 @@ void MYSQL_LOG::new_file(bool inside_mutex) We log the whole file name for log file as the user may decide to change base names at some point. */ - Rotate_log_event r(new_name+dirname_length(new_name)); + THD* thd = current_thd; + Rotate_log_event r(thd,new_name+dirname_length(new_name)); + r.set_log_seq(0, this); + // this log rotation could have been initiated by a master of + // the slave running with log-bin + // we set the flag on rotate event to prevent inifinite log rotation + // loop + if(thd && slave_thd && thd == slave_thd) + r.flags |= LOG_EVENT_FORCED_ROTATE_F; r.write(&log_file); VOID(pthread_cond_broadcast(&COND_binlog_update)); } @@ -627,9 +638,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, return 0; } -/* Write to binary log in a format to be used for replication */ -bool MYSQL_LOG::write(Query_log_event* event_info) +bool MYSQL_LOG::write(Log_event* event_info) { /* In most cases this is only called if 'is_open()' is true */ bool error=0; @@ -641,34 +651,42 @@ bool MYSQL_LOG::write(Query_log_event* event_info) if (is_open()) { THD *thd=event_info->thd; - IO_CACHE *file = (event_info->cache_stmt ? &thd->transaction.trans_log : + const char* db = event_info->get_db(); +#ifdef USING_TRANSACTIONS + IO_CACHE *file = ((event_info->get_cache_stmt() && thd) ? + &thd->transaction.trans_log : &log_file); - if ((!(thd->options & OPTION_BIN_LOG) && +#else + IO_CACHE *file = &log_file; +#endif + if ((thd && !(thd->options & OPTION_BIN_LOG) && (thd->master_access & PROCESS_ACL)) || - !db_ok(event_info->db, binlog_do_db, binlog_ignore_db)) + (db && !db_ok(db, binlog_do_db, binlog_ignore_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); return 0; } error=1; - if (thd->last_insert_id_used) + if (thd && thd->last_insert_id_used) { - Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id); - if(thd->server_id) - e.server_id = thd->server_id; + Intvar_log_event e(thd,(uchar)LAST_INSERT_ID_EVENT,thd->last_insert_id); + e.set_log_seq(thd, this); + if (thd->server_id) + e.server_id = thd->server_id; if (e.write(file)) goto err; } - if (thd->insert_id_used) + if (thd && thd->insert_id_used) { - Intvar_log_event e((uchar)INSERT_ID_EVENT, thd->last_insert_id); - if(thd->server_id) - e.server_id = thd->server_id; + Intvar_log_event e(thd,(uchar)INSERT_ID_EVENT,thd->last_insert_id); + e.set_log_seq(thd, this); + if (thd->server_id) + e.server_id = thd->server_id; if (e.write(file)) goto err; } - if (thd->convert_set) + if (thd && thd->convert_set) { char buf[1024] = "SET CHARACTER SET "; char* p = strend(buf); @@ -677,10 +695,12 @@ bool MYSQL_LOG::write(Query_log_event* event_info) // just in case somebody wants it later thd->query_length = (uint)(p - buf); Query_log_event e(thd, buf); + e.set_log_seq(thd, this); if (e.write(file)) goto err; thd->query_length = save_query_length; // clean up } + event_info->set_log_seq(thd, this); if (event_info->write(file) || file == &log_file && flush_io_cache(file)) goto err; @@ -704,6 +724,15 @@ err: return error; } +uint MYSQL_LOG::next_file_id() +{ + uint res; + pthread_mutex_lock(&LOCK_log); + res = file_id++; + pthread_mutex_unlock(&LOCK_log); + return res; +} + /* Write a cached log entry to the binary log We only come here if there is something in the cache. @@ -761,42 +790,6 @@ err: } -bool MYSQL_LOG::write(Load_log_event* event_info) -{ - bool error=0; - bool should_rotate = 0; - - if (inited) - { - VOID(pthread_mutex_lock(&LOCK_log)); - if (is_open()) - { - THD *thd=event_info->thd; - if ((thd->options & OPTION_BIN_LOG) || - !(thd->master_access & PROCESS_ACL)) - { - if (event_info->write(&log_file) || flush_io_cache(&log_file)) - { - if (!write_error) - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); - error=write_error=1; - } - should_rotate = (my_b_tell(&log_file) >= max_binlog_size); - VOID(pthread_cond_broadcast(&COND_binlog_update)); - } - } - - if(should_rotate) - new_file(1); // inside mutex - - VOID(pthread_mutex_unlock(&LOCK_log)); - } - - - return error; -} - - /* Write update log in a format suitable for incremental backup */ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, @@ -928,6 +921,7 @@ void MYSQL_LOG::close(bool exiting) if (log_type == LOG_BIN) { Stop_log_event s; + s.set_log_seq(0, this); s.write(&log_file); VOID(pthread_cond_broadcast(&COND_binlog_update)); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 521e0f7765f..ecf4e815b49 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -20,25 +20,326 @@ #pragma implementation // gcc: Class implementation #endif #include "mysql_priv.h" +#include "slave.h" #endif /* MYSQL_CLIENT */ - -static void pretty_print_char(FILE* file, int c) +#ifdef MYSQL_CLIENT +static void pretty_print_str(FILE* file, char* str, int len) { + char* end = str + len; fputc('\'', file); - switch(c) { - case '\n': fprintf(file, "\\n"); break; - case '\r': fprintf(file, "\\r"); break; - case '\\': fprintf(file, "\\\\"); break; - case '\b': fprintf(file, "\\b"); break; - case '\'': fprintf(file, "\\'"); break; - case 0 : fprintf(file, "\\0"); break; - default: - fputc(c, file); - break; + while (str < end) + { + char c; + switch ((c=*str++)) { + case '\n': fprintf(file, "\\n"); break; + case '\r': fprintf(file, "\\r"); break; + case '\\': fprintf(file, "\\\\"); break; + case '\b': fprintf(file, "\\b"); break; + case '\t': fprintf(file, "\\t"); break; + case '\'': fprintf(file, "\\'"); break; + case 0 : fprintf(file, "\\0"); break; + default: + fputc(c, file); + break; + } } fputc('\'', file); } +#endif + +#ifndef MYSQL_CLIENT + + +static void pretty_print_str(String* packet, char* str, int len) +{ + char* end = str + len; + packet->append('\''); + while (str < end) + { + char c; + switch((c=*str++)) { + case '\n': packet->append( "\\n"); break; + case '\r': packet->append( "\\r"); break; + case '\\': packet->append( "\\\\"); break; + case '\b': packet->append( "\\b"); break; + case '\t': packet->append( "\\t"); break; + case '\'': packet->append( "\\'"); break; + case 0 : packet->append( "\\0"); break; + default: + packet->append((char)c); + break; + } + } + packet->append('\''); +} + +static inline char* slave_load_file_stem(char*buf, uint file_id, + int event_server_id) +{ + fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",4+32); + buf = strend(buf); + buf = int10_to_str(::server_id, buf, 10); + *buf++ = '-'; + buf = int10_to_str(event_server_id, buf, 10); + *buf++ = '-'; + return int10_to_str(file_id, buf, 10); +} + +#endif + +const char* Log_event::get_type_str() +{ + switch(get_type_code()) + { + case START_EVENT: return "Start"; + case STOP_EVENT: return "Stop"; + case QUERY_EVENT: return "Query"; + case ROTATE_EVENT: return "Rotate"; + case INTVAR_EVENT: return "Intvar"; + case LOAD_EVENT: return "Load"; + case NEW_LOAD_EVENT: return "New_load"; + case SLAVE_EVENT: return "Slave"; + case CREATE_FILE_EVENT: return "Create_file"; + case APPEND_BLOCK_EVENT: return "Append_block"; + case DELETE_FILE_EVENT: return "Delete_file"; + case EXEC_LOAD_EVENT: return "Exec_load"; + default: /* impossible */ return "Unknown"; + } +} + +#ifndef MYSQL_CLIENT +Log_event::Log_event(THD* thd_arg, uint16 flags_arg): + exec_time(0), + flags(flags_arg),cached_event_len(0), + temp_buf(0),thd(thd_arg) +{ + if (thd) + { + server_id = thd->server_id; + log_seq = thd->log_seq; + when = thd->start_time; + } + else + { + server_id = ::server_id; + log_seq = 0; + when = time(NULL); + } +} +#endif + +Log_event::Log_event(const char* buf):cached_event_len(0),temp_buf(0) +{ + when = uint4korr(buf); + server_id = uint4korr(buf + SERVER_ID_OFFSET); + log_seq = uint4korr(buf + LOG_SEQ_OFFSET); + flags = uint2korr(buf + FLAGS_OFFSET); +#ifndef MYSQL_CLIENT + thd = 0; +#endif +} + + +#ifndef MYSQL_CLIENT + +int Log_event::exec_event(struct st_master_info* mi) +{ + if (mi) + { + thd->log_seq = 0; + mi->inc_pos(get_event_len(), log_seq); + flush_master_info(mi); + } + return 0; +} + +void Log_event::pack_info(String* packet) +{ + net_store_data(packet, "", 0); +} + +void Query_log_event::pack_info(String* packet) +{ + char buf[256]; + String tmp(buf, sizeof(buf)); + tmp.length(0); + if(db && db_len) + { + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); + } + + if(query && q_len) + tmp.append(query, q_len); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); +} + +void Start_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + + tmp.append("Server ver: "); + tmp.append(server_version); + tmp.append(", Binlog ver: "); + tmp.append(llstr(binlog_version, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + +void Load_log_event::pack_info(String* packet) +{ + char buf[256]; + String tmp(buf, sizeof(buf)); + tmp.length(0); + if(db && db_len) + { + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); + } + + tmp.append("LOAD DATA INFILE '"); + tmp.append(fname, fname_len); + tmp.append("' ", 2); + if(sql_ex.opt_flags && REPLACE_FLAG ) + tmp.append(" REPLACE "); + else if(sql_ex.opt_flags && IGNORE_FLAG ) + tmp.append(" IGNORE "); + + tmp.append("INTO TABLE "); + tmp.append(table_name); + if (sql_ex.field_term_len) + { + tmp.append(" FIELDS TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); + } + + if (sql_ex.enclosed_len) + { + if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) + tmp.append(" OPTIONALLY "); + tmp.append( " ENCLOSED BY "); + pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); + } + + if (sql_ex.escaped_len) + { + tmp.append( " ESCAPED BY "); + pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); + } + + if (sql_ex.line_term_len) + { + tmp.append(" LINES TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + } + + if (sql_ex.line_start_len) + { + tmp.append(" LINES STARTING BY "); + pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); + } + + if ((int)skip_lines > 0) + tmp.append( " IGNORE %ld LINES ", (long) skip_lines); + + if (num_fields) + { + uint i; + const char* field = fields; + tmp.append(" ("); + for(i = 0; i < num_fields; i++) + { + if(i) + tmp.append(" ,"); + tmp.append( field); + + field += field_lens[i] + 1; + } + tmp.append(')'); + } + + net_store_data(packet, tmp.ptr(), tmp.length()); +} + +void Rotate_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append(new_log_ident, ident_len); + tmp.append(";pos="); + tmp.append(llstr(pos,buf)); + if(flags & LOG_EVENT_FORCED_ROTATE_F) + tmp.append("; forced by master"); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + +void Intvar_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append(get_var_type_name()); + tmp.append('='); + tmp.append(llstr(val, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + +void Slave_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append("host="); + tmp.append(master_host); + tmp.append(",port="); + tmp.append(llstr(master_port,buf)); + tmp.append(",log="); + tmp.append(master_log); + tmp.append(",pos="); + tmp.append(llstr(master_pos,buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} + + +void Log_event::init_show_field_list(List<Item>* field_list) +{ + field_list->push_back(new Item_empty_string("Log_name", 20)); + field_list->push_back(new Item_empty_string("Pos", 20)); + field_list->push_back(new Item_empty_string("Event_type", 20)); + field_list->push_back(new Item_empty_string("Server_id", 20)); + field_list->push_back(new Item_empty_string("Log_seq", 20)); + field_list->push_back(new Item_empty_string("Info", 20)); +} + +int Log_event::net_send(THD* thd, const char* log_name, ulong pos) +{ + String* packet = &thd->packet; + const char* p = strrchr(log_name, FN_LIBCHAR); + const char* event_type; + if (p) + log_name = p + 1; + + packet->length(0); + net_store_data(packet, log_name, strlen(log_name)); + net_store_data(packet, (longlong)pos); + event_type = get_type_str(); + net_store_data(packet, event_type, strlen(event_type)); + net_store_data(packet, server_id); + net_store_data(packet, log_seq); + pack_info(packet); + return my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); +} + +#endif int Query_log_event::write(IO_CACHE* file) { @@ -52,7 +353,6 @@ int Log_event::write(IO_CACHE* file) int Log_event::write_header(IO_CACHE* file) { - // make sure to change this when the header gets bigger char buf[LOG_EVENT_HEADER_LEN]; char* pos = buf; int4store(pos, (ulong) when); // timestamp @@ -63,6 +363,10 @@ int Log_event::write_header(IO_CACHE* file) long tmp=get_data_size() + LOG_EVENT_HEADER_LEN; int4store(pos, tmp); pos += 4; + int4store(pos, log_seq); + pos += 4; + int2store(pos, flags); + pos += 2; return (my_b_write(file, (byte*) buf, (uint) (pos - buf))); } @@ -124,91 +428,57 @@ Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock) Log_event* Log_event::read_log_event(IO_CACHE* file) #endif { - time_t timestamp; - uint32 server_id; - - char buf[LOG_EVENT_HEADER_LEN-4]; -#ifndef MYSQL_CLIENT - if(log_lock) pthread_mutex_lock(log_lock); -#endif - if (my_b_read(file, (byte *) buf, sizeof(buf))) + char head[LOG_EVENT_HEADER_LEN]; +#ifndef MYSQL_CLIENT + if(log_lock) pthread_mutex_lock(log_lock); +#endif + if (my_b_read(file, (byte *) head, sizeof(head))) { - UNLOCK_MUTEX - return NULL; + UNLOCK_MUTEX; + return 0; } - timestamp = uint4korr(buf); - server_id = uint4korr(buf + 5); - - switch(buf[EVENT_TYPE_OFFSET]) - { - case QUERY_EVENT: + + uint data_len = uint4korr(head + EVENT_LEN_OFFSET); + char* buf = 0; + const char* error = 0; + Log_event* res = 0; + + if (data_len > max_allowed_packet) { - Query_log_event* q = new Query_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - if (!q->query) - { - delete q; - q=NULL; - } - return q; + error = "Event too big"; + goto err; } - - case LOAD_EVENT: + + if (data_len < LOG_EVENT_HEADER_LEN) { - Load_log_event* l = new Load_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - if (!l->table_name) - { - delete l; - l=NULL; - } - return l; + error = "Event too small"; + goto err; } - - case ROTATE_EVENT: + // some events use the extra byte to null-terminate strings + if (!(buf = my_malloc(data_len+1, MYF(MY_WME)))) { - Rotate_log_event* r = new Rotate_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - if (!r->new_log_ident) - { - delete r; - r=NULL; - } - return r; + error = "Out of memory"; + goto err; } - - case INTVAR_EVENT: + buf[data_len] = 0; + memcpy(buf, head, LOG_EVENT_HEADER_LEN); + if(my_b_read(file, (byte*) buf + LOG_EVENT_HEADER_LEN, + data_len - LOG_EVENT_HEADER_LEN)) { - Intvar_log_event* e = new Intvar_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - if (e->type == INVALID_INT_EVENT) - { - delete e; - e=NULL; - } - return e; + error = "read error"; + goto err; } - - case START_EVENT: - { - Start_log_event* e = new Start_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - return e; - } - case STOP_EVENT: - { - Stop_log_event* e = new Stop_log_event(file, timestamp, server_id); - UNLOCK_MUTEX - return e; - } - default: - break; + if((res = read_log_event(buf, data_len))) + res->register_temp_buf(buf); +err: + UNLOCK_MUTEX; + if(error) + { + sql_print_error(error); + my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } - - // default - UNLOCK_MUTEX - return NULL; + return res; } Log_event* Log_event::read_log_event(const char* buf, int event_len) @@ -217,52 +487,58 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len) (uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET)) return NULL; // general sanity check - will fail on a partial read + Log_event* ev = NULL; + switch(buf[EVENT_TYPE_OFFSET]) { case QUERY_EVENT: - { - Query_log_event* q = new Query_log_event(buf, event_len); - if (!q->query) - { - delete q; - return NULL; - } - - return q; - } - + ev = new Query_log_event(buf, event_len); + break; case LOAD_EVENT: - { - Load_log_event* l = new Load_log_event(buf, event_len); - if (!l->table_name) - { - delete l; - return NULL; - } - - return l; - } - + case NEW_LOAD_EVENT: + ev = new Load_log_event(buf, event_len); + break; case ROTATE_EVENT: - { - Rotate_log_event* r = new Rotate_log_event(buf, event_len); - if (!r->new_log_ident) - { - delete r; - return NULL; - } - - return r; - } - case START_EVENT: return new Start_log_event(buf); - case STOP_EVENT: return new Stop_log_event(buf); - case INTVAR_EVENT: return new Intvar_log_event(buf); + ev = new Rotate_log_event(buf, event_len); + break; + case SLAVE_EVENT: + ev = new Slave_log_event(buf, event_len); + break; + case CREATE_FILE_EVENT: + ev = new Create_file_log_event(buf, event_len); + break; + case APPEND_BLOCK_EVENT: + ev = new Append_block_log_event(buf, event_len); + break; + case DELETE_FILE_EVENT: + ev = new Delete_file_log_event(buf, event_len); + break; + case EXEC_LOAD_EVENT: + ev = new Execute_load_log_event(buf, event_len); + break; + case START_EVENT: + ev = new Start_log_event(buf); + break; + case STOP_EVENT: + ev = new Stop_log_event(buf); + break; + case INTVAR_EVENT: + ev = new Intvar_log_event(buf); + break; default: break; } - return NULL; // default value + if (!ev) return 0; + if (!ev->is_valid()) + { + delete ev; + return 0; + } + ev->cached_event_len = event_len; + return ev; } +#ifdef MYSQL_CLIENT void Log_event::print_header(FILE* file) { fputc('#', file); @@ -318,6 +594,7 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) { + char buf[22]; if (short_form) return; @@ -326,51 +603,27 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) if (new_log_ident) my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, MYF(MY_NABP | MY_WME)); - fprintf(file, "\n"); + fprintf(file, "pos=%s\n", llstr(pos, buf)); fflush(file); } -Rotate_log_event::Rotate_log_event(IO_CACHE* file, time_t when_arg, - uint32 server_id): - Log_event(when_arg, 0, 0, server_id),new_log_ident(NULL),alloced(0) -{ - char *tmp_ident; - char buf[4]; - - if (my_b_read(file, (byte*) buf, sizeof(buf))) - return; - ulong event_len; - event_len = uint4korr(buf); - if (event_len < ROTATE_EVENT_OVERHEAD) - return; - - ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD); - if (!(tmp_ident = (char*) my_malloc((uint)ident_len, MYF(MY_WME)))) - return; - if (my_b_read( file, (byte*) tmp_ident, (uint) ident_len)) - { - my_free((gptr) tmp_ident, MYF(0)); - return; - } - - new_log_ident = tmp_ident; - alloced = 1; -} +#endif /* #ifdef MYSQL_CLIENT */ Start_log_event::Start_log_event(const char* buf) :Log_event(buf) { - buf += EVENT_LEN_OFFSET + 4; // skip even length - binlog_version = uint2korr(buf); - memcpy(server_version, buf + 2, sizeof(server_version)); - created = uint4korr(buf + 2 + sizeof(server_version)); + binlog_version = uint2korr(buf + LOG_EVENT_HEADER_LEN + + ST_BINLOG_VER_OFFSET); + memcpy(server_version, buf + ST_SERVER_VER_OFFSET + LOG_EVENT_HEADER_LEN, + ST_SERVER_VER_LEN); + created = uint4korr(buf + ST_CREATED_OFFSET + LOG_EVENT_HEADER_LEN); } int Start_log_event::write_data(IO_CACHE* file) { - char buff[sizeof(server_version)+2+4]; - int2store(buff,binlog_version); - memcpy(buff+2,server_version,sizeof(server_version)); - int4store(buff+2+sizeof(server_version),created); + char buff[START_HEADER_LEN]; + int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); + memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); + int4store(buff + ST_CREATED_OFFSET,created); return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); } @@ -382,8 +635,10 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len): if(event_len < ROTATE_EVENT_OVERHEAD) return; + pos = uint8korr(buf + R_POS_OFFSET + LOG_EVENT_HEADER_LEN); ident_len = (uchar)(event_len - ROTATE_EVENT_OVERHEAD); - if (!(new_log_ident = (char*) my_memdup((byte*) buf + LOG_EVENT_HEADER_LEN, + if (!(new_log_ident = (char*) my_memdup((byte*) buf + R_IDENT_OFFSET + + LOG_EVENT_HEADER_LEN, (uint) ident_len, MYF(MY_WME)))) return; @@ -392,43 +647,28 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len): int Rotate_log_event::write_data(IO_CACHE* file) { - return my_b_write(file, (byte*) new_log_ident, (uint) ident_len) ? -1 :0; + char buf[ROTATE_HEADER_LEN]; + int8store(buf, pos + R_POS_OFFSET); + return my_b_write(file, (byte*)buf, ROTATE_HEADER_LEN) || + my_b_write(file, (byte*)new_log_ident, (uint) ident_len); } -Query_log_event::Query_log_event(IO_CACHE* file, time_t when_arg, - uint32 server_id): - Log_event(when_arg,0,0,server_id),data_buf(0),query(NULL),db(NULL) -{ - char buf[QUERY_HEADER_LEN + 4]; - ulong data_len; - if (my_b_read(file, (byte*) buf, sizeof(buf))) - return; // query == NULL will tell the - // caller there was a problem - data_len = uint4korr(buf); - if (data_len < QUERY_EVENT_OVERHEAD) - return; // tear-drop attack protection :) - - data_len -= QUERY_EVENT_OVERHEAD; - exec_time = uint4korr(buf + 8); - db_len = (uint)buf[12]; - error_code = uint2korr(buf + 13); - - /* Allocate one byte extra for end \0 */ - if (!(data_buf = (char*) my_malloc(data_len+1, MYF(MY_WME)))) - return; - if (my_b_read( file, (byte*) data_buf, data_len)) +#ifndef MYSQL_CLIENT +Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, + bool using_trans): + Log_event(thd_arg), data_buf(0), query(query_arg), db(thd_arg->db), + q_len(thd_arg->query_length), + error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), + thread_id(thd_arg->thread_id), + cache_stmt(using_trans && + (thd_arg->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) { - my_free((gptr) data_buf, MYF(0)); - data_buf = 0; - return; + time_t end_time; + time(&end_time); + exec_time = (ulong) (end_time - thd->start_time); + db_len = (db) ? (uint32) strlen(db) : 0; } - - thread_id = uint4korr(buf + 4); - db = data_buf; - query=data_buf + db_len + 1; - q_len = data_len - 1 - db_len; - *((char*) query + q_len) = 0; // Safety -} +#endif Query_log_event::Query_log_event(const char* buf, int event_len): Log_event(buf),data_buf(0), query(NULL), db(NULL) @@ -436,24 +676,26 @@ Query_log_event::Query_log_event(const char* buf, int event_len): if ((uint)event_len < QUERY_EVENT_OVERHEAD) return; ulong data_len; - buf += EVENT_LEN_OFFSET; data_len = event_len - QUERY_EVENT_OVERHEAD; + - exec_time = uint4korr(buf + 8); - error_code = uint2korr(buf + 13); + exec_time = uint4korr(buf + LOG_EVENT_HEADER_LEN + Q_EXEC_TIME_OFFSET); + error_code = uint2korr(buf + LOG_EVENT_HEADER_LEN + Q_ERR_CODE_OFFSET); if (!(data_buf = (char*) my_malloc(data_len + 1, MYF(MY_WME)))) return; - memcpy(data_buf, buf + QUERY_HEADER_LEN + 4, data_len); - thread_id = uint4korr(buf + 4); + memcpy(data_buf, buf + LOG_EVENT_HEADER_LEN + Q_DATA_OFFSET, data_len); + thread_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + Q_THREAD_ID_OFFSET); db = data_buf; - db_len = (uint)buf[12]; + db_len = (uint)buf[LOG_EVENT_HEADER_LEN + Q_DB_LEN_OFFSET]; query=data_buf + db_len + 1; q_len = data_len - 1 - db_len; *((char*)query+q_len) = 0; } +#ifdef MYSQL_CLIENT + void Query_log_event::print(FILE* file, bool short_form, char* last_db) { char buff[40],*end; // Enough for SET TIMESTAMP @@ -482,52 +724,49 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, ";\n"); } +#endif + int Query_log_event::write_data(IO_CACHE* file) { if (!query) return -1; char buf[QUERY_HEADER_LEN]; - char* pos = buf; - int4store(pos, thread_id); - pos += 4; - int4store(pos, exec_time); - pos += 4; - *pos++ = (char)db_len; - int2store(pos, error_code); - pos += 2; + int4store(buf + Q_THREAD_ID_OFFSET, thread_id); + int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); + buf[Q_DB_LEN_OFFSET] = (char)db_len; + int2store(buf + Q_ERR_CODE_OFFSET, error_code); - return (my_b_write(file, (byte*) buf, (uint)(pos - buf)) || + return (my_b_write(file, (byte*) buf, QUERY_HEADER_LEN) || my_b_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) || my_b_write(file, (byte*) query, q_len)) ? -1 : 0; } -Intvar_log_event:: Intvar_log_event(IO_CACHE* file, time_t when_arg, - uint32 server_id) - :Log_event(when_arg,0,0,server_id), type(INVALID_INT_EVENT) +Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf) { - char buf[9+4]; - if (!my_b_read(file, (byte*) buf, sizeof(buf))) - { - type = buf[4]; - val = uint8korr(buf+1+4); - } + buf += LOG_EVENT_HEADER_LEN; + type = buf[I_TYPE_OFFSET]; + val = uint8korr(buf+I_VAL_OFFSET); } -Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf) +const char* Intvar_log_event::get_var_type_name() { - buf += LOG_EVENT_HEADER_LEN; - type = buf[0]; - val = uint8korr(buf+1); + switch(type) + { + case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID"; + case INSERT_ID_EVENT: return "INSERT_ID"; + default: /* impossible */ return "UNKNOWN"; + } } int Intvar_log_event::write_data(IO_CACHE* file) { char buf[9]; - buf[0] = type; - int8store(buf + 1, val); + buf[I_TYPE_OFFSET] = type; + int8store(buf + I_VAL_OFFSET, val); return my_b_write(file, (byte*) buf, sizeof(buf)); } +#ifdef MYSQL_CLIENT void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) { char llbuff[22]; @@ -551,100 +790,232 @@ void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) fflush(file); } +#endif -int Load_log_event::write_data(IO_CACHE* file) +int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; - int4store(buf, thread_id); - int4store(buf + 4, exec_time); - int4store(buf + 8, skip_lines); - buf[12] = (char)table_name_len; - buf[13] = (char)db_len; - int4store(buf + 14, num_fields); - - if(my_b_write(file, (byte*)buf, sizeof(buf)) || - my_b_write(file, (byte*)&sql_ex, sizeof(sql_ex))) - return 1; + int4store(buf + L_THREAD_ID_OFFSET, thread_id); + int4store(buf + L_EXEC_TIME_OFFSET, exec_time); + int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); + buf[L_TBL_LEN_OFFSET] = (char)table_name_len; + buf[L_DB_LEN_OFFSET] = (char)db_len; + int4store(buf + L_NUM_FIELDS_OFFSET, num_fields); + return my_b_write(file, (byte*)buf, LOAD_HEADER_LEN); +} +int Load_log_event::write_data_body(IO_CACHE* file) +{ + if (sql_ex.write_data(file)) return 1; if (num_fields && fields && field_lens) { if(my_b_write(file, (byte*)field_lens, num_fields) || my_b_write(file, (byte*)fields, field_block_len)) return 1; } - if(my_b_write(file, (byte*)table_name, table_name_len + 1) || + return my_b_write(file, (byte*)table_name, table_name_len + 1) || my_b_write(file, (byte*)db, db_len + 1) || - my_b_write(file, (byte*)fname, fname_len)) - return 1; - return 0; + my_b_write(file, (byte*)fname, fname_len); } -Load_log_event::Load_log_event(IO_CACHE* file, time_t when, uint32 server_id): - Log_event(when,0,0,server_id),data_buf(0),num_fields(0), - fields(0),field_lens(0),field_block_len(0), - table_name(0),db(0),fname(0) +#define WRITE_STR(name) my_b_write(file,(byte*)&name ## _len, 1) || \ + my_b_write(file,(byte*)name,name ## _len) +#define OLD_EX_INIT(name) old_ex.##name = *name + +int sql_ex_info::write_data(IO_CACHE* file) { - char buf[LOAD_HEADER_LEN + 4]; - ulong data_len; - if (my_b_read(file, (byte*)buf, sizeof(buf)) || - my_b_read(file, (byte*)&sql_ex, sizeof(sql_ex))) - return; + if (new_format()) + { + return WRITE_STR(field_term) || WRITE_STR(enclosed) || + WRITE_STR(line_term) || WRITE_STR(line_start) || + WRITE_STR(escaped) || my_b_write(file,(byte*)&opt_flags,1); + } + else + { + old_sql_ex old_ex; + OLD_EX_INIT(field_term); + OLD_EX_INIT(enclosed); + OLD_EX_INIT(line_term); + OLD_EX_INIT(line_start); + OLD_EX_INIT(escaped); + old_ex.opt_flags = opt_flags; + old_ex.empty_flags = empty_flags; + return my_b_write(file,(byte*)&old_ex,sizeof(old_ex)); + } +} - data_len = uint4korr(buf) - LOAD_EVENT_OVERHEAD; - if (!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME)))) - return; - if (my_b_read(file, (byte*)data_buf, data_len)) - return; - copy_log_event(buf,data_len); +#define READ_STR(name) name ## _len = *buf++;\ + if (buf >= buf_end) return 0;\ + name = buf; \ + buf += name ## _len; \ + if (buf >= buf_end) return 0; + +#define READ_OLD_STR(name) name ## _len = 1; \ + name = buf++; \ + if (buf >= buf_end) return 0; + +#define FIX_OLD_LEN(name,NAME) if (empty_flags & NAME ## _EMPTY) \ + name ## _len = 0 + +char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) +{ + cached_new_format = use_new_format; + if (use_new_format) + { + READ_STR(field_term); + READ_STR(enclosed); + READ_STR(line_term); + READ_STR(line_start); + READ_STR(escaped); + opt_flags = *buf++; + } + else + { + READ_OLD_STR(field_term); + READ_OLD_STR(enclosed); + READ_OLD_STR(line_term); + READ_OLD_STR(line_start); + READ_OLD_STR(escaped); + opt_flags = *buf++; + empty_flags = *buf++; + FIX_OLD_LEN(field_term,FIELD_TERM); + FIX_OLD_LEN(enclosed,ENCLOSED); + FIX_OLD_LEN(line_term,LINE_TERM); + FIX_OLD_LEN(line_start,LINE_START); + FIX_OLD_LEN(escaped,ESCAPED); + } + return buf; } + +#ifndef MYSQL_CLIENT +Load_log_event::Load_log_event(THD* thd, sql_exchange* ex, + const char* db_arg, const char* table_name_arg, + List<Item>& fields_arg, enum enum_duplicates handle_dup): + Log_event(thd),thread_id(thd->thread_id), + num_fields(0),fields(0),field_lens(0),field_block_len(0), + table_name(table_name_arg), + db(db_arg), + fname(ex->file_name) + { + time_t end_time; + time(&end_time); + exec_time = (ulong) (end_time - thd->start_time); + db_len = (db) ? (uint32) strlen(db) : 0; + table_name_len = (table_name) ? (uint32) strlen(table_name) : 0; + fname_len = (fname) ? (uint) strlen(fname) : 0; + sql_ex.field_term = (char*)ex->field_term->ptr(); + sql_ex.field_term_len = ex->field_term->length(); + sql_ex.enclosed = (char*)ex->enclosed->ptr(); + sql_ex.enclosed_len = ex->enclosed->length(); + sql_ex.line_term = (char*)ex->line_term->ptr(); + sql_ex.line_term_len = ex->line_term->length(); + sql_ex.line_start = (char*)ex->line_start->ptr(); + sql_ex.line_start_len = ex->line_start->length(); + sql_ex.escaped = (char*)ex->escaped->ptr(); + sql_ex.escaped_len = ex->escaped->length(); + sql_ex.opt_flags = 0; + sql_ex.cached_new_format = -1; + + if(ex->dumpfile) + sql_ex.opt_flags |= DUMPFILE_FLAG; + if(ex->opt_enclosed) + sql_ex.opt_flags |= OPT_ENCLOSED_FLAG; + + sql_ex.empty_flags = 0; + + switch(handle_dup) + { + case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break; + case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break; + case DUP_ERROR: break; + } + + + if(!ex->field_term->length()) + sql_ex.empty_flags |= FIELD_TERM_EMPTY; + if(!ex->enclosed->length()) + sql_ex.empty_flags |= ENCLOSED_EMPTY; + if(!ex->line_term->length()) + sql_ex.empty_flags |= LINE_TERM_EMPTY; + if(!ex->line_start->length()) + sql_ex.empty_flags |= LINE_START_EMPTY; + if(!ex->escaped->length()) + sql_ex.empty_flags |= ESCAPED_EMPTY; + + skip_lines = ex->skip_lines; + + List_iterator<Item> li(fields_arg); + field_lens_buf.length(0); + fields_buf.length(0); + Item* item; + while((item = li++)) + { + num_fields++; + uchar len = (uchar) strlen(item->name); + field_block_len += len + 1; + fields_buf.append(item->name, len + 1); + field_lens_buf.append((char*)&len, 1); + } + + field_lens = (const uchar*)field_lens_buf.ptr(); + fields = fields_buf.ptr(); + } + +#endif + +// the caller must do buf[event_len] = 0 before he starts using the +// constructed event Load_log_event::Load_log_event(const char* buf, int event_len): - Log_event(buf),data_buf(0),num_fields(0),fields(0), + Log_event(buf),num_fields(0),fields(0), field_lens(0),field_block_len(0), table_name(0),db(0),fname(0) { - ulong data_len; - - if((uint)event_len < (LOAD_EVENT_OVERHEAD + LOG_EVENT_HEADER_LEN)) - return; - buf += EVENT_LEN_OFFSET; - memcpy(&sql_ex, buf + LOAD_HEADER_LEN + 4, sizeof(sql_ex)); - data_len = event_len; - - if(!(data_buf = (char*)my_malloc(data_len + 1, MYF(MY_WME)))) + if (!event_len) // derived class, will call copy_log_event() itself return; - memcpy(data_buf, buf + 22 + sizeof(sql_ex), data_len); - copy_log_event(buf, data_len); + copy_log_event(buf, event_len); } -void Load_log_event::copy_log_event(const char *buf, ulong data_len) +int Load_log_event::copy_log_event(const char *buf, ulong event_len) { - thread_id = uint4korr(buf+4); - exec_time = uint4korr(buf+8); - skip_lines = uint4korr(buf + 12); - table_name_len = (uint)buf[16]; - db_len = (uint)buf[17]; - num_fields = uint4korr(buf + 18); + uint data_len; + char* buf_end = (char*)buf + event_len; + thread_id = uint4korr(buf + L_THREAD_ID_OFFSET + LOG_EVENT_HEADER_LEN); + exec_time = uint4korr(buf + L_EXEC_TIME_OFFSET + LOG_EVENT_HEADER_LEN); + skip_lines = uint4korr(buf + L_SKIP_LINES_OFFSET + LOG_EVENT_HEADER_LEN); + table_name_len = (uint)buf[L_TBL_LEN_OFFSET + LOG_EVENT_HEADER_LEN]; + db_len = (uint)buf[L_DB_LEN_OFFSET + LOG_EVENT_HEADER_LEN]; + num_fields = uint4korr(buf + L_NUM_FIELDS_OFFSET + LOG_EVENT_HEADER_LEN); + int body_offset = get_data_body_offset(); + if ((int)event_len < body_offset) + return 1; + //sql_ex.init() on success returns the pointer to the first byte after + //the sql_ex structure, which is the start of field lengths array + if (!(field_lens=(uchar*)sql_ex.init((char*)buf + body_offset, + buf_end, + buf[EVENT_TYPE_OFFSET] != LOAD_EVENT))) + return 1; + + data_len = event_len - body_offset; if (num_fields > data_len) // simple sanity check against corruption - return; - - field_lens = (uchar*) data_buf; + return 1; uint i; for (i = 0; i < num_fields; i++) { field_block_len += (uint)field_lens[i] + 1; } fields = (char*)field_lens + num_fields; - - *((char*)data_buf+data_len) = 0; table_name = fields + field_block_len; db = table_name + table_name_len + 1; fname = db + db_len + 1; - fname_len = data_len - 2 - db_len - table_name_len - num_fields - - field_block_len; + int type_code = get_type_code(); + fname_len = strlen(fname); + // null termination is accomplished by the caller doing buf[event_len]=0 + return 0; } +#ifdef MYSQL_CLIENT void Load_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -666,7 +1037,7 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) if(db && db[0] && !same_db) fprintf(file, "use %s;\n", db); - fprintf(file, "LOAD DATA INFILE '%s' ", fname); + fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname); if(sql_ex.opt_flags && REPLACE_FLAG ) fprintf(file," REPLACE "); @@ -674,36 +1045,36 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file," IGNORE "); fprintf(file, "INTO TABLE %s ", table_name); - if(!(sql_ex.empty_flags & FIELD_TERM_EMPTY)) + if(sql_ex.field_term) { fprintf(file, " FIELDS TERMINATED BY "); - pretty_print_char(file, sql_ex.field_term); + pretty_print_str(file, sql_ex.field_term, sql_ex.field_term_len); } - if(!(sql_ex.empty_flags & ENCLOSED_EMPTY)) + if(sql_ex.enclosed) { if(sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) fprintf(file," OPTIONALLY "); fprintf(file, " ENCLOSED BY "); - pretty_print_char(file, sql_ex.enclosed); + pretty_print_str(file, sql_ex.enclosed, sql_ex.enclosed_len); } - if(!(sql_ex.empty_flags & ESCAPED_EMPTY)) + if (sql_ex.escaped) { fprintf(file, " ESCAPED BY "); - pretty_print_char(file, sql_ex.escaped); + pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); } - if(!(sql_ex.empty_flags & LINE_TERM_EMPTY)) + if (sql_ex.line_term) { fprintf(file," LINES TERMINATED BY "); - pretty_print_char(file, sql_ex.line_term); + pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); } - if(!(sql_ex.empty_flags & LINE_START_EMPTY)) + if (sql_ex.line_start) { fprintf(file," LINES STARTING BY "); - pretty_print_char(file, sql_ex.line_start); + pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len); } if((int)skip_lines > 0) @@ -728,8 +1099,16 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, ";\n"); } +#endif /* #ifdef MYSQL_CLIENT */ + #ifndef MYSQL_CLIENT +void Log_event::set_log_seq(THD* thd, MYSQL_LOG* log) + { + log_seq = (thd && thd->log_seq) ? thd->log_seq++ : log->log_seq++; + } + + void Load_log_event::set_fields(List<Item> &fields) { uint i; @@ -742,4 +1121,746 @@ void Load_log_event::set_fields(List<Item> &fields) } +Slave_log_event::Slave_log_event(THD* thd_arg,struct st_master_info* mi): + Log_event(thd_arg),mem_pool(0),master_host(0) +{ + if(!mi->inited) + return; + pthread_mutex_lock(&mi->lock); + master_host_len = strlen(mi->host); + master_log_len = strlen(mi->log_file_name); + // on OOM, just do not initialize the structure and print the error + if((mem_pool = (char*)my_malloc(get_data_size() + 1, + MYF(MY_WME)))) + { + master_host = mem_pool + SL_MASTER_HOST_OFFSET ; + memcpy(master_host, mi->host, master_host_len + 1); + master_log = master_host + master_host_len + 1; + memcpy(master_log, mi->log_file_name, master_log_len + 1); + master_port = mi->port; + master_pos = mi->pos; + } + else + sql_print_error("Out of memory while recording slave event"); + pthread_mutex_unlock(&mi->lock); +} + + +#endif + + +Slave_log_event::~Slave_log_event() +{ + my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR)); +} + +#ifdef MYSQL_CLIENT + +void Slave_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + if(short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "Slave: master_host='%s' master_port=%d \ + master_log=%s master_pos=%s\n", master_host, master_port, master_log, + llstr(master_pos, llbuff)); +} + +#endif + +int Slave_log_event::get_data_size() +{ + return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET; +} + +int Slave_log_event::write_data(IO_CACHE* file) +{ + int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos); + int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port); + // log and host are already there + return my_b_write(file, (byte*)mem_pool, get_data_size()); +} + +void Slave_log_event::init_from_mem_pool(int data_size) +{ + master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET); + master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET); + master_host = mem_pool + SL_MASTER_HOST_OFFSET; + master_host_len = strlen(master_host); + // safety + master_log = master_host + master_host_len + 1; + if(master_log > mem_pool + data_size) + { + master_host = 0; + return; + } + master_log_len = strlen(master_log); +} + +Slave_log_event::Slave_log_event(const char* buf, int event_len): + Log_event(buf),mem_pool(0),master_host(0) +{ + event_len -= LOG_EVENT_HEADER_LEN; + if(event_len < 0) + return; + if(!(mem_pool = (char*)my_malloc(event_len + 1, MYF(MY_WME)))) + return; + memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len); + mem_pool[event_len] = 0; + init_from_mem_pool(event_len); +} + +#ifndef MYSQL_CLIENT +Create_file_log_event::Create_file_log_event(THD* thd_arg, sql_exchange* ex, + const char* db_arg, const char* table_name_arg, + List<Item>& fields_arg, enum enum_duplicates handle_dup, + char* block_arg, uint block_len_arg): + Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup), + fake_base(0),block(block_arg),block_len(block_len_arg), + file_id(thd_arg->file_id = mysql_bin_log.next_file_id()) +{ + sql_ex.force_new_format(); +} +#endif + +int Create_file_log_event::write_data_body(IO_CACHE* file) +{ + int res; + if ((res = Load_log_event::write_data_body(file)) || fake_base) + return res; + return my_b_write(file, "", 1) || my_b_write(file, block, block_len); +} + +int Create_file_log_event::write_data_header(IO_CACHE* file) +{ + int res; + if ((res = Load_log_event::write_data_header(file)) || fake_base) + return res; + char buf[CREATE_FILE_HEADER_LEN]; + int4store(buf + CF_FILE_ID_OFFSET, file_id); + return my_b_write(file, buf, CREATE_FILE_HEADER_LEN); +} + +int Create_file_log_event::write_base(IO_CACHE* file) +{ + int res; + fake_base = 1; // pretend we are Load event + res = write(file); + fake_base = 0; + return res; +} + +Create_file_log_event::Create_file_log_event(const char* buf, int len): + Load_log_event(buf,0),fake_base(0),block(0) +{ + int block_offset; + if (copy_log_event(buf,len)) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + + + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET); + block_offset = LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() + + CREATE_FILE_HEADER_LEN + 1; // 1 for \0 terminating fname + if (len < block_offset) + return; + block = (char*)buf + block_offset; + block_len = len - block_offset; +} +#ifdef MYSQL_CLIENT +void Create_file_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + Load_log_event::print(file, 1, last_db); + fprintf(file, " file_id=%d, block_len=%d\n", file_id, block_len); +} #endif + +#ifndef MYSQL_CLIENT +void Create_file_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append("db="); + tmp.append(db, db_len); + tmp.append(";table="); + tmp.append(table_name, table_name_len); + tmp.append(";file_id="); + tmp.append(llstr(file_id,buf)); + tmp.append(";block_len="); + tmp.append(llstr(block_len,buf)); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); +} +#endif + +#ifndef MYSQL_CLIENT +Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, + uint block_len_arg): + Log_event(thd_arg), block(block_arg),block_len(block_len_arg), + file_id(thd_arg->file_id) +{ +} +#endif + +Append_block_log_event::Append_block_log_event(const char* buf, int len): + Log_event(buf),block(0) +{ + if((uint)len < APPEND_BLOCK_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); + block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD; + block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; +} + +int Append_block_log_event::write_data(IO_CACHE* file) +{ + char buf[APPEND_BLOCK_HEADER_LEN]; + int4store(buf + AB_FILE_ID_OFFSET, file_id); + return my_b_write(file, buf, APPEND_BLOCK_HEADER_LEN) || + my_b_write(file, block, block_len); +} + +#ifdef MYSQL_CLIENT +void Append_block_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Append_block: file_id=%d, block_len=%d\n", + file_id, block_len); +} +#endif +#ifndef MYSQL_CLIENT +void Append_block_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append(";file_id="); + tmp.append(llstr(file_id,buf)); + tmp.append(";block_len="); + tmp.append(llstr(block_len,buf)); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); +} +#endif + +#ifndef MYSQL_CLIENT +Delete_file_log_event::Delete_file_log_event(THD* thd_arg): + Log_event(thd_arg),file_id(thd_arg->file_id) +{ +} +#endif + +Delete_file_log_event::Delete_file_log_event(const char* buf, int len): + Log_event(buf),file_id(0) +{ + if((uint)len < DELETE_FILE_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); +} + +int Delete_file_log_event::write_data(IO_CACHE* file) +{ + char buf[DELETE_FILE_HEADER_LEN]; + int4store(buf + DF_FILE_ID_OFFSET, file_id); + return my_b_write(file, buf, DELETE_FILE_HEADER_LEN); +} + +#ifdef MYSQL_CLIENT +void Delete_file_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Delete_file: file_id=%d\n", + file_id); +} +#endif +#ifndef MYSQL_CLIENT +void Delete_file_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append(";file_id="); + tmp.append(llstr(file_id,buf)); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); +} +#endif + +#ifndef MYSQL_CLIENT +Execute_load_log_event::Execute_load_log_event(THD* thd_arg): + Log_event(thd_arg),file_id(thd_arg->file_id) +{ +} +#endif + +Execute_load_log_event::Execute_load_log_event(const char* buf,int len): + Log_event(buf),file_id(0) +{ + if((uint)len < EXEC_LOAD_EVENT_OVERHEAD) + return; + file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); +} + +int Execute_load_log_event::write_data(IO_CACHE* file) +{ + char buf[EXEC_LOAD_HEADER_LEN]; + int4store(buf + EL_FILE_ID_OFFSET, file_id); + return my_b_write(file, buf, EXEC_LOAD_HEADER_LEN); +} + +#ifdef MYSQL_CLIENT +void Execute_load_log_event::print(FILE* file, bool short_form, + char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "#Exec_load: file_id=%d\n", + file_id); +} +#endif +#ifndef MYSQL_CLIENT +void Execute_load_log_event::pack_info(String* packet) +{ + char buf1[256]; + String tmp(buf1, sizeof(buf1)); + tmp.length(0); + char buf[22]; + tmp.append(";file_id="); + tmp.append(llstr(file_id,buf)); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); +} +#endif + +#ifndef MYSQL_CLIENT +int Query_log_event::exec_event(struct st_master_info* mi) +{ + int expected_error,actual_error = 0; + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db = rewrite_db((char*)db); + if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + { + thd->query = (char*)query; + thd->set_time((time_t)when); + thd->current_tablenr = 0; + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->query_id = query_id++; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + thd->query_error = 0; // clear error + thd->net.last_errno = 0; + thd->net.last_error[0] = 0; + thd->slave_proxy_id = thread_id; // for temp tables + + // sanity check to make sure the master did not get a really bad + // error on the query + if (!check_expected_error(thd, (expected_error = error_code))) + { + mysql_parse(thd, thd->query, q_len); + if (expected_error != + (actual_error = thd->net.last_errno) && expected_error) + { + const char* errmsg = "Slave: did not get the expected error\ + running query from master - expected: '%s'(%d), got '%s'(%d)"; + sql_print_error(errmsg, ER_SAFE(expected_error), + expected_error, + actual_error ? thd->net.last_error:"no error", + actual_error); + thd->query_error = 1; + } + else if (expected_error == actual_error) + { + thd->query_error = 0; + *last_slave_error = 0; + last_slave_errno = 0; + } + } + else + { + // master could be inconsistent, abort and tell DBA to check/fix it + thd->db = thd->query = 0; + thd->convert_set = 0; + close_thread_tables(thd); + free_root(&thd->mem_root,0); + return 1; + } + } + thd->db = 0; // prevent db from being freed + thd->query = 0; // just to be sure + // assume no convert for next query unless set explictly + thd->convert_set = 0; + close_thread_tables(thd); + + if (thd->query_error || thd->fatal_error) + { + slave_print_error(actual_error, "error '%s' on query '%s'", + actual_error ? thd->net.last_error : + "unexpected success or fatal error", query); + free_root(&thd->mem_root,0); + return 1; + } + free_root(&thd->mem_root,0); + return Log_event::exec_event(mi); +} + +int Load_log_event::exec_event(NET* net, struct st_master_info* mi) +{ + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db = rewrite_db((char*)db); + thd->query = 0; + thd->query_error = 0; + + if(db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + { + thd->set_time((time_t)when); + thd->current_tablenr = 0; + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->query_id = query_id++; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + + TABLE_LIST tables; + bzero((char*) &tables,sizeof(tables)); + tables.db = thd->db; + tables.name = tables.real_name = (char*)table_name; + tables.lock_type = TL_WRITE; + // the table will be opened in mysql_load + if(table_rules_on && !tables_ok(thd, &tables)) + { + if (net) + skip_load_data_infile(net); + } + else + { + char llbuff[22]; + enum enum_duplicates handle_dup = DUP_IGNORE; + if(sql_ex.opt_flags && REPLACE_FLAG) + handle_dup = DUP_REPLACE; + sql_exchange ex((char*)fname, sql_ex.opt_flags && + DUMPFILE_FLAG ); + +#define SET_EX(name) String name(sql_ex.name,sql_ex.name ## _len);\ + ex.name = &name; + + SET_EX(field_term); + SET_EX(enclosed); + SET_EX(line_term); + SET_EX(line_start); + SET_EX(escaped); + + ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG); + if(sql_ex.empty_flags & FIELD_TERM_EMPTY) + ex.field_term->length(0); + + ex.skip_lines = skip_lines; + List<Item> fields; + set_fields(fields); + thd->slave_proxy_id = thd->thread_id; + if (net) + { + // mysql_load will use thd->net to read the file + thd->net.vio = net->vio; + // make sure the client does not get confused + // about the packet sequence + thd->net.pkt_nr = net->pkt_nr; + } + if(mysql_load(thd, &ex, &tables, fields, handle_dup, net != 0, + TL_WRITE)) + thd->query_error = 1; + if(thd->cuted_fields) + sql_print_error("Slave: load data infile at position %s in log \ +'%s' produced %d warning(s)", llstr(mi->pos,llbuff), RPL_LOG_NAME, + thd->cuted_fields ); + if(net) + net->pkt_nr = thd->net.pkt_nr; + } + } + else + { + // we will just ask the master to send us /dev/null if we do not + // want to load the data + if (net) + skip_load_data_infile(net); + } + + thd->net.vio = 0; + thd->db = 0;// prevent db from being freed + close_thread_tables(thd); + if(thd->query_error) + { + int sql_error = thd->net.last_errno; + if(!sql_error) + sql_error = ER_UNKNOWN_ERROR; + + slave_print_error(sql_error, "Slave: Error '%s' running load data infile ", + ER_SAFE(sql_error)); + free_root(&thd->mem_root,0); + return 1; + } + free_root(&thd->mem_root,0); + + if(thd->fatal_error) + { + sql_print_error("Slave: Fatal error running LOAD DATA INFILE "); + return 1; + } + + return Log_event::exec_event(mi); +} + +int Start_log_event::exec_event(struct st_master_info* mi) +{ + close_temporary_tables(thd); + return Log_event::exec_event(mi); +} + +int Stop_log_event::exec_event(struct st_master_info* mi) +{ + if(mi->pos > 4) // stop event should be ignored after rotate event + { + close_temporary_tables(thd); + mi->inc_pos(get_event_len(), log_seq); + flush_master_info(mi); + } + thd->log_seq = 0; + return 0; +} + +int Rotate_log_event::exec_event(struct st_master_info* mi) +{ + bool rotate_binlog = 0, write_slave_event = 0; + char* log_name = mi->log_file_name; + pthread_mutex_lock(&mi->lock); + + // rotate local binlog only if the name of remote has changed + if (!*log_name || !(log_name[ident_len] == 0 && + !memcmp(log_name, new_log_ident, ident_len))) + { + write_slave_event = (!(flags & LOG_EVENT_FORCED_ROTATE_F) + && mysql_bin_log.is_open()); + rotate_binlog = (*log_name && write_slave_event); + memcpy(log_name, new_log_ident,ident_len ); + log_name[ident_len] = 0; + } + mi->pos = pos; + mi->last_log_seq = log_seq; +#ifndef DBUG_OFF + if (abort_slave_event_count) + ++events_till_abort; +#endif + if (rotate_binlog) + { + mysql_bin_log.new_file(); + mi->last_log_seq = 0; + } + pthread_cond_broadcast(&mi->cond); + pthread_mutex_unlock(&mi->lock); + flush_master_info(mi); + + if (write_slave_event) + { + Slave_log_event s(thd, mi); + if (s.master_host) + { + s.set_log_seq(0, &mysql_bin_log); + s.server_id = ::server_id; + mysql_bin_log.write(&s); + } + } + thd->log_seq = 0; + return 0; +} + +int Intvar_log_event::exec_event(struct st_master_info* mi) +{ + switch(type) + { + case LAST_INSERT_ID_EVENT: + thd->last_insert_id_used = 1; + thd->last_insert_id = val; + break; + case INSERT_ID_EVENT: + thd->next_insert_id = val; + break; + } + mi->inc_pending(get_event_len()); + return 0; +} + +int Slave_log_event::exec_event(struct st_master_info* mi) +{ + if(mysql_bin_log.is_open()) + mysql_bin_log.write(this); + return Log_event::exec_event(mi); +} + +int Create_file_log_event::exec_event(struct st_master_info* mi) +{ + char fname_buf[FN_REFLEN+10]; + char* p,*p1; + int fd = -1; + IO_CACHE file; + int error = 1; + p = slave_load_file_stem(fname_buf, file_id, server_id); + memcpy(p, ".info", 6); + bzero((char*)&file, sizeof(file)); + if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + MYF(MY_WME))) < 0 || + init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, + MYF(MY_WME|MY_NABP))) + { + slave_print_error(my_errno, "Could not open file '%s'", fname_buf); + goto err; + } + + // a trick to avoid allocating another buffer + memcpy(p, ".data", 6); + fname = fname_buf; + fname_len = (uint)(p-fname) + 5; + if (write_base(&file)) + { + memcpy(p, ".info", 6); // to have it right in the error message + slave_print_error(my_errno, "Could not write to file '%s'", fname_buf); + goto err; + } + end_io_cache(&file); + my_close(fd, MYF(0)); + + // fname_buf now already has .data, not .info, because we did our trick + if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + MYF(MY_WME))) < 0) + { + slave_print_error(my_errno, "Could not open file '%s'", fname_buf); + goto err; + } + if (my_write(fd, block, block_len, MYF(MY_WME+MY_NABP))) + { + slave_print_error(my_errno, "Write to '%s' failed", fname_buf); + goto err; + } + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + error=0; +err: + if (error) + end_io_cache(&file); + if (fd >= 0) + my_close(fd, MYF(0)); + return error ? 1 : Log_event::exec_event(mi); +} + +int Delete_file_log_event::exec_event(struct st_master_info* mi) +{ + char fname[FN_REFLEN+10]; + char* p; + p = slave_load_file_stem(fname, file_id, server_id); + memcpy(p, ".data", 6); + (void)my_delete(fname, MYF(MY_WME)); + memcpy(p, ".info", 6); + (void)my_delete(fname, MYF(MY_WME)); + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + return Log_event::exec_event(mi); +} + +int Append_block_log_event::exec_event(struct st_master_info* mi) +{ + char fname[FN_REFLEN+10]; + char* p; + int fd = -1; + int error = 1; + p = slave_load_file_stem(fname, file_id, server_id); + memcpy(p, ".data", 6); + if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0) + { + slave_print_error(my_errno, "Could not open file '%s'", fname); + goto err; + } + if (my_write(fd, block, block_len, MYF(MY_WME+MY_NABP))) + { + slave_print_error(my_errno, "Write to '%s' failed", fname); + goto err; + } + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + error=0; +err: + if (fd >= 0) + my_close(fd, MYF(0)); + return error ? error : Log_event::exec_event(mi); +} + +int Execute_load_log_event::exec_event(struct st_master_info* mi) +{ + char fname[FN_REFLEN+10]; + char* p; + int fd = -1; + int error = 1; + int save_options; + IO_CACHE file; + Load_log_event* lev = 0; + p = slave_load_file_stem(fname, file_id, server_id); + memcpy(p, ".info", 6); + bzero((char*)&file, sizeof(file)); + if ((fd = my_open(fname, O_RDONLY|O_BINARY, MYF(MY_WME))) < 0 || + init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0, + MYF(MY_WME|MY_NABP))) + { + slave_print_error(my_errno, "Could not open file '%s'", fname); + goto err; + } + if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,0)) + || lev->get_type_code() != NEW_LOAD_EVENT) + { + slave_print_error(0, "File '%s' appears corrupted", fname); + goto err; + } + // we want to disable binary logging in slave thread + // because we need the file events to appear in the same order + // as they do on the master relative to other events, so that we + // can preserve ascending order of log sequence numbers - needed + // to handle failover + save_options = thd->options; + thd->options &= ~ (ulong) OPTION_BIN_LOG; + lev->thd = thd; + if (lev->exec_event(0,0)) + { + slave_print_error(my_errno, "Failed executing load from '%s'", fname); + thd->options = save_options; + goto err; + } + thd->options = save_options; + (void)my_delete(fname, MYF(MY_WME)); + memcpy(p, ".data", 6); + (void)my_delete(fname, MYF(MY_WME)); + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + error = 0; +err: + delete lev; + end_io_cache(&file); + if (fd >= 0) + my_close(fd, MYF(0)); + return error ? error : Log_event::exec_event(mi); +} + + +#endif + + + + + + + diff --git a/sql/log_event.h b/sql/log_event.h index 94f7cce0e35..ef795e75e2c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -34,40 +34,192 @@ #define LOG_READ_TOO_LARGE -7 #define LOG_EVENT_OFFSET 4 -#define BINLOG_VERSION 1 +#define BINLOG_VERSION 2 + +/* we could have used SERVER_VERSION_LENGTH, but this introduces an + obscure dependency - if somebody decided to change SERVER_VERSION_LENGTH + this would have broke the replication protocol +*/ +#define ST_SERVER_VER_LEN 50 + +#define DUMPFILE_FLAG 0x1 +#define OPT_ENCLOSED_FLAG 0x2 +#define REPLACE_FLAG 0x4 +#define IGNORE_FLAG 0x8 + +#define FIELD_TERM_EMPTY 0x1 +#define ENCLOSED_EMPTY 0x2 +#define LINE_TERM_EMPTY 0x4 +#define LINE_START_EMPTY 0x8 +#define ESCAPED_EMPTY 0x10 + +struct old_sql_ex + { + char field_term; + char enclosed; + char line_term; + char line_start; + char escaped; + char opt_flags; + char empty_flags; + }; + + +struct sql_ex_info + { + char* field_term; + char* enclosed; + char* line_term; + char* line_start; + char* escaped; + uchar field_term_len,enclosed_len,line_term_len,line_start_len, + escaped_len; + char opt_flags; + char empty_flags; + int cached_new_format; + + // store in new format even if old is possible + void force_new_format() { cached_new_format = 1;} + int data_size() { return new_format() ? + field_term_len + enclosed_len + line_term_len + + line_start_len + escaped_len + 6 : 7;} + int write_data(IO_CACHE* file); + char* init(char* buf,char* buf_end,bool use_new_format); + bool new_format() + { + return (cached_new_format != -1) ? cached_new_format : + (cached_new_format=(field_term_len > 1 || + enclosed_len > 1 || + line_term_len > 1 || line_start_len > 1 || + escaped_len > 1)); + } + } ; + +/* Binary log consists of events. Each event has a fixed length header, + followed by possibly variable ( depending on the type of event) length + data body. The data body consists of an optional fixed length segment + (post-header), and an optional variable length segment. See #defines and + comments below for the format specifics +*/ + + +/* event-specific post-header sizes */ +#define LOG_EVENT_HEADER_LEN 19 +#define QUERY_HEADER_LEN (4 + 4 + 1 + 2) +#define LOAD_HEADER_LEN (4 + 4 + 4 + 1 +1 + 4) +#define START_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4) +#define ROTATE_HEADER_LEN 8 +#define CREATE_FILE_HEADER_LEN 4 +#define APPEND_BLOCK_HEADER_LEN 4 +#define EXEC_LOAD_HEADER_LEN 4 +#define DELETE_FILE_HEADER_LEN 4 + +/* event header offsets */ -#define LOG_EVENT_HEADER_LEN 13 -#define QUERY_HEADER_LEN (sizeof(uint32) + sizeof(uint32) + \ - sizeof(uchar) + sizeof(uint16)) -#define LOAD_HEADER_LEN (sizeof(uint32) + sizeof(uint32) + \ - + sizeof(uint32) + 2 + sizeof(uint32)) -#define EVENT_LEN_OFFSET 9 #define EVENT_TYPE_OFFSET 4 +#define SERVER_ID_OFFSET 5 +#define EVENT_LEN_OFFSET 9 +#define LOG_SEQ_OFFSET 13 +#define FLAGS_OFFSET 17 + +/* start event post-header */ + +#define ST_BINLOG_VER_OFFSET 0 +#define ST_SERVER_VER_OFFSET 2 +#define ST_CREATED_OFFSET (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN) + +/* slave event post-header */ + +#define SL_MASTER_PORT_OFFSET 8 +#define SL_MASTER_POS_OFFSET 0 +#define SL_MASTER_HOST_OFFSET 10 + +/* query event post-header */ + +#define Q_THREAD_ID_OFFSET 0 +#define Q_EXEC_TIME_OFFSET 4 +#define Q_DB_LEN_OFFSET 8 +#define Q_ERR_CODE_OFFSET 9 +#define Q_DATA_OFFSET QUERY_HEADER_LEN + +/* Intvar event post-header */ + +#define I_TYPE_OFFSET 0 +#define I_VAL_OFFSET 1 + +/* Load event post-header */ + +#define L_THREAD_ID_OFFSET 0 +#define L_EXEC_TIME_OFFSET 4 +#define L_SKIP_LINES_OFFSET 8 +#define L_DB_LEN_OFFSET 12 +#define L_TBL_LEN_OFFSET 13 +#define L_NUM_FIELDS_OFFSET 14 +#define L_SQL_EX_OFFSET 18 +#define L_DATA_OFFSET LOAD_HEADER_LEN + +/* Rotate event post-header */ + +#define R_POS_OFFSET 0 +#define R_IDENT_OFFSET 8 + +#define CF_FILE_ID_OFFSET 0 +#define CF_DATA_OFFSET CREATE_FILE_HEADER_LEN + +#define AB_FILE_ID_OFFSET 0 +#define AB_DATA_OFFSET APPEND_BLOCK_HEADER_LEN + +#define EL_FILE_ID_OFFSET 0 + +#define DF_FILE_ID_OFFSET 0 + #define QUERY_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN) -#define ROTATE_EVENT_OVERHEAD LOG_EVENT_HEADER_LEN -#define LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+LOAD_HEADER_LEN+sizeof(sql_ex_info)) +#define QUERY_DATA_OFFSET (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN) +#define ROTATE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+ROTATE_HEADER_LEN) +#define LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+LOAD_HEADER_LEN) +#define CREATE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+\ + +LOAD_HEADER_LEN+CREATE_FILE_HEADER_LEN) +#define DELETE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+DELETE_FILE_HEADER_LEN) +#define EXEC_LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+EXEC_LOAD_HEADER_LEN) +#define APPEND_BLOCK_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+APPEND_BLOCK_HEADER_LEN) + #define BINLOG_MAGIC "\xfe\x62\x69\x6e" +#define LOG_EVENT_TIME_F 0x1 +#define LOG_EVENT_FORCED_ROTATE_F 0x2 + enum Log_event_type { START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4, INTVAR_EVENT=5, - LOAD_EVENT=6}; + LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8, + APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11, + NEW_LOAD_EVENT=12}; enum Int_event_type { INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2 }; #ifndef MYSQL_CLIENT class String; +class MYSQL_LOG; +class THD; #endif extern uint32 server_id; +struct st_master_info; + class Log_event { public: time_t when; ulong exec_time; - int valid_exec_time; // if false, the exec time setting is bogus uint32 server_id; + uint32 log_seq; + uint16 flags; + int cached_event_len; + char* temp_buf; +#ifndef MYSQL_CLIENT + THD* thd; +#endif static void *operator new(size_t size) { @@ -81,30 +233,39 @@ public: int write(IO_CACHE* file); int write_header(IO_CACHE* file); - virtual int write_data(IO_CACHE* file __attribute__((unused))) { return 0; } + virtual int write_data(IO_CACHE* file) + { return write_data_header(file) || write_data_body(file); } + virtual int write_data_header(IO_CACHE* file __attribute__((unused))) + { return 0; } + virtual int write_data_body(IO_CACHE* file __attribute__((unused))) + { return 0; } virtual Log_event_type get_type_code() = 0; - Log_event(time_t when_arg, ulong exec_time_arg = 0, - int valid_exec_time_arg = 0, uint32 server_id_arg = 0): - when(when_arg), exec_time(exec_time_arg), - valid_exec_time(valid_exec_time_arg) - { - server_id = server_id_arg ? server_id_arg : (::server_id); - } - - Log_event(const char* buf): valid_exec_time(0) - { - when = uint4korr(buf); - server_id = uint4korr(buf + 5); - } - - virtual ~Log_event() {} - + virtual bool is_valid() = 0; + virtual bool get_cache_stmt() { return 0; } + Log_event(const char* buf); +#ifndef MYSQL_CLIENT + Log_event(THD* thd_arg, uint16 flags_arg = 0); +#endif + virtual ~Log_event() { free_temp_buf();} + void register_temp_buf(char* buf) { temp_buf = buf; } + void free_temp_buf() + { + if (temp_buf) + { + my_free(temp_buf, MYF(0)); + temp_buf = 0; + } + } virtual int get_data_size() { return 0;} + virtual int get_data_body_offset() { return 0; } + int get_event_len() { return cached_event_len ? cached_event_len : + (cached_event_len = LOG_EVENT_HEADER_LEN + get_data_size()); } +#ifdef MYSQL_CLIENT virtual void print(FILE* file, bool short_form = 0, char* last_db = 0) = 0; - void print_timestamp(FILE* file, time_t *ts = 0); void print_header(FILE* file); - +#endif + #ifndef MYSQL_CLIENT // if mutex is 0, the read will proceed without mutex static Log_event* read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock); @@ -112,10 +273,20 @@ public: static Log_event* read_log_event(IO_CACHE* file); #endif static Log_event* read_log_event(const char* buf, int event_len); + const char* get_type_str(); #ifndef MYSQL_CLIENT static int read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock); + void set_log_seq(THD* thd, MYSQL_LOG* log); + virtual void pack_info(String* packet); + int net_send(THD* thd, const char* log_name, ulong pos); + static void init_show_field_list(List<Item>* field_list); + virtual int exec_event(struct st_master_info* mi); + virtual const char* get_db() + { + return thd ? thd->db : 0; + } #endif }; @@ -135,27 +306,16 @@ public: uint16 error_code; ulong thread_id; #if !defined(MYSQL_CLIENT) - THD* thd; bool cache_stmt; - Query_log_event(THD* thd_arg, const char* query_arg, bool using_trans=0): - Log_event(thd_arg->start_time,0,1,thd_arg->server_id), data_buf(0), - query(query_arg), db(thd_arg->db), q_len(thd_arg->query_length), - error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), - thread_id(thd_arg->thread_id), thd(thd_arg), - cache_stmt(using_trans && - (thd_arg->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) - { - time_t end_time; - time(&end_time); - exec_time = (ulong) (end_time - thd->start_time); - db_len = (db) ? (uint32) strlen(db) : 0; - // do not log stray system errors such as EE_WRITE - if (error_code < ERRMOD) - error_code = 0; - } + + Query_log_event(THD* thd_arg, const char* query_arg, + bool using_trans=0); + const char* get_db() { return db; } + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); + bool get_cache_stmt() { return cache_stmt; } #endif - Query_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg); Query_log_event(const char* buf, int event_len); ~Query_log_event() { @@ -167,46 +327,55 @@ public: Log_event_type get_type_code() { return QUERY_EVENT; } int write(IO_CACHE* file); int write_data(IO_CACHE* file); // returns 0 on success, -1 on error + bool is_valid() { return query != 0; } int get_data_size() { return q_len + db_len + 2 + - sizeof(uint32) // thread_id - + sizeof(uint32) // exec_time - + sizeof(uint16) // error_code + 4 // thread_id + + 4 // exec_time + + 2 // error_code ; } - +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif }; -#define DUMPFILE_FLAG 0x1 -#define OPT_ENCLOSED_FLAG 0x2 -#define REPLACE_FLAG 0x4 -#define IGNORE_FLAG 0x8 - -#define FIELD_TERM_EMPTY 0x1 -#define ENCLOSED_EMPTY 0x2 -#define LINE_TERM_EMPTY 0x4 -#define LINE_START_EMPTY 0x8 -#define ESCAPED_EMPTY 0x10 +class Slave_log_event: public Log_event +{ +protected: + char* mem_pool; + void init_from_mem_pool(int data_size); +public: + char* master_host; + int master_host_len; + uint16 master_port; + char* master_log; + int master_log_len; + ulonglong master_pos; +#ifndef MYSQL_CLIENT + Slave_log_event(THD* thd_arg, struct st_master_info* mi); + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif + + Slave_log_event(const char* buf, int event_len); + ~Slave_log_event(); + int get_data_size(); + bool is_valid() { return master_host != 0; } + Log_event_type get_type_code() { return SLAVE_EVENT; } +#ifdef MYSQL_CLIENT + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif + int write_data(IO_CACHE* file ); -struct sql_ex_info - { - char field_term; - char enclosed; - char line_term; - char line_start; - char escaped; - char opt_flags; // flags for the options - char empty_flags; // flags to indicate which of the terminating charact - } ; +}; class Load_log_event: public Log_event { protected: - char* data_buf; - void copy_log_event(const char *buf, ulong data_len); + int copy_log_event(const char *buf, ulong event_len); public: ulong thread_id; @@ -217,7 +386,6 @@ public: const char* fields; const uchar* field_lens; uint32 field_block_len; - const char* table_name; const char* db; @@ -226,88 +394,31 @@ public: sql_ex_info sql_ex; #if !defined(MYSQL_CLIENT) - THD* thd; String field_lens_buf; String fields_buf; - Load_log_event(THD* thd, sql_exchange* ex, const char* table_name_arg, - List<Item>& fields_arg, enum enum_duplicates handle_dup ): - Log_event(thd->start_time),data_buf(0),thread_id(thd->thread_id), - num_fields(0),fields(0),field_lens(0),field_block_len(0), - table_name(table_name_arg), - db(thd->db), - fname(ex->file_name), - thd(thd) - { - time_t end_time; - time(&end_time); - exec_time = (ulong) (end_time - thd->start_time); - valid_exec_time = 1; - db_len = (db) ? (uint32) strlen(db) : 0; - table_name_len = (table_name) ? (uint32) strlen(table_name) : 0; - fname_len = (fname) ? (uint) strlen(fname) : 0; - sql_ex.field_term = (*ex->field_term)[0]; - sql_ex.enclosed = (*ex->enclosed)[0]; - sql_ex.line_term = (*ex->line_term)[0]; - sql_ex.line_start = (*ex->line_start)[0]; - sql_ex.escaped = (*ex->escaped)[0]; - sql_ex.opt_flags = 0; - if(ex->dumpfile) - sql_ex.opt_flags |= DUMPFILE_FLAG; - if(ex->opt_enclosed) - sql_ex.opt_flags |= OPT_ENCLOSED_FLAG; - - sql_ex.empty_flags = 0; - - switch(handle_dup) - { - case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break; - case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break; - case DUP_ERROR: break; - } - - if(!ex->field_term->length()) - sql_ex.empty_flags |= FIELD_TERM_EMPTY; - if(!ex->enclosed->length()) - sql_ex.empty_flags |= ENCLOSED_EMPTY; - if(!ex->line_term->length()) - sql_ex.empty_flags |= LINE_TERM_EMPTY; - if(!ex->line_start->length()) - sql_ex.empty_flags |= LINE_START_EMPTY; - if(!ex->escaped->length()) - sql_ex.empty_flags |= ESCAPED_EMPTY; - - skip_lines = ex->skip_lines; - - List_iterator<Item> li(fields_arg); - field_lens_buf.length(0); - fields_buf.length(0); - Item* item; - while((item = li++)) - { - num_fields++; - uchar len = (uchar) strlen(item->name); - field_block_len += len + 1; - fields_buf.append(item->name, len + 1); - field_lens_buf.append((char*)&len, 1); - } - - field_lens = (const uchar*)field_lens_buf.ptr(); - fields = fields_buf.ptr(); - } + + Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg, + const char* table_name_arg, + List<Item>& fields_arg, enum enum_duplicates handle_dup); void set_fields(List<Item> &fields_arg); + void pack_info(String* packet); + const char* get_db() { return db; } + int exec_event(struct st_master_info* mi) + { + return exec_event(thd->slave_net,mi); + } + int exec_event(NET* net, struct st_master_info* mi); #endif - Load_log_event(IO_CACHE * file, time_t when, uint32 server_id_arg); Load_log_event(const char* buf, int event_len); ~Load_log_event() { - if (data_buf) - { - my_free((gptr) data_buf, MYF(0)); - } } - Log_event_type get_type_code() { return LOAD_EVENT; } - int write_data(IO_CACHE* file); // returns 0 on success, -1 on error + Log_event_type get_type_code() { return sql_ex.new_format() ? + NEW_LOAD_EVENT: LOAD_EVENT; } + int write_data_header(IO_CACHE* file); + int write_data_body(IO_CACHE* file); + bool is_valid() { return table_name != 0; } int get_data_size() { return table_name_len + 2 + db_len + 2 + fname_len @@ -315,11 +426,13 @@ public: + 4 // exec_time + 4 // skip_lines + 4 // field block len - + sizeof(sql_ex) + field_block_len + num_fields*sizeof(uchar) ; + + sql_ex.data_size() + field_block_len + num_fields; ; } - + int get_data_body_offset() { return LOAD_EVENT_OVERHEAD; } +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif }; extern char server_version[SERVER_VERSION_LENGTH]; @@ -329,35 +442,30 @@ class Start_log_event: public Log_event public: uint32 created; uint16 binlog_version; - char server_version[50]; - - Start_log_event() :Log_event(time(NULL)),binlog_version(BINLOG_VERSION) + char server_version[ST_SERVER_VER_LEN]; +#ifndef MYSQL_CLIENT + Start_log_event() :Log_event((THD*)0),binlog_version(BINLOG_VERSION) { created = (uint32) when; - memcpy(server_version, ::server_version, sizeof(server_version)); - } - Start_log_event(IO_CACHE* file, time_t when_arg, uint32 server_id_arg) : - Log_event(when_arg, 0, 0, server_id_arg) - { - char buf[sizeof(server_version) + 2 + 4 + 4]; - if (my_b_read(file, (byte*) buf, sizeof(buf))) - return; - binlog_version = uint2korr(buf+4); - memcpy(server_version, buf + 6, sizeof(server_version)); - server_version[sizeof(server_version)-1]=0; - created = uint4korr(buf + 6 + sizeof(server_version)); + memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); } +#endif Start_log_event(const char* buf); - ~Start_log_event() {} Log_event_type get_type_code() { return START_EVENT;} int write_data(IO_CACHE* file); + bool is_valid() { return 1; } int get_data_size() { - // sizeof(binlog_version) + sizeof(server_version) sizeof(created) - return 2 + sizeof(server_version) + 4; + return START_HEADER_LEN; } +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif }; class Intvar_log_event: public Log_event @@ -365,37 +473,47 @@ class Intvar_log_event: public Log_event public: ulonglong val; uchar type; - Intvar_log_event(uchar type_arg, ulonglong val_arg) - :Log_event(time(NULL)),val(val_arg),type(type_arg) +#ifndef MYSQL_CLIENT + Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg) + :Log_event(thd_arg),val(val_arg),type(type_arg) {} - Intvar_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg); +#endif Intvar_log_event(const char* buf); ~Intvar_log_event() {} Log_event_type get_type_code() { return INTVAR_EVENT;} + const char* get_var_type_name(); int get_data_size() { return sizeof(type) + sizeof(val);} int write_data(IO_CACHE* file); + bool is_valid() { return 1; } +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif - +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif }; class Stop_log_event: public Log_event { public: - Stop_log_event() :Log_event(time(NULL)) +#ifndef MYSQL_CLIENT + Stop_log_event() :Log_event((THD*)0) {} - Stop_log_event(IO_CACHE* file, time_t when_arg, uint32 server_id_arg): - Log_event(when_arg,0,0,server_id_arg) - { - byte skip[4]; - my_b_read(file, skip, sizeof(skip)); // skip the event length - } +#endif Stop_log_event(const char* buf):Log_event(buf) { } ~Stop_log_event() {} Log_event_type get_type_code() { return STOP_EVENT;} + bool is_valid() { return 1; } +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + int exec_event(struct st_master_info* mi); +#endif }; class Rotate_log_event: public Log_event @@ -403,16 +521,18 @@ class Rotate_log_event: public Log_event public: const char* new_log_ident; uchar ident_len; + ulonglong pos; bool alloced; - - Rotate_log_event(const char* new_log_ident_arg, uint ident_len_arg = 0) : - Log_event(time(NULL)), +#ifndef MYSQL_CLIENT + Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg, + uint ident_len_arg = 0,ulonglong pos_arg = 4) : + Log_event(thd_arg), new_log_ident(new_log_ident_arg), - ident_len(ident_len_arg ? ident_len_arg : (uint) strlen(new_log_ident_arg)), + ident_len(ident_len_arg ? ident_len_arg : + (uint) strlen(new_log_ident_arg)), pos(pos_arg), alloced(0) {} - - Rotate_log_event(IO_CACHE* file, time_t when, uint32 server_id_arg) ; +#endif Rotate_log_event(const char* buf, int event_len); ~Rotate_log_event() { @@ -420,10 +540,152 @@ public: my_free((gptr) new_log_ident, MYF(0)); } Log_event_type get_type_code() { return ROTATE_EVENT;} - int get_data_size() { return ident_len;} + int get_data_size() { return ident_len + ROTATE_HEADER_LEN;} + bool is_valid() { return new_log_ident != 0; } + int write_data(IO_CACHE* file); +#ifdef MYSQL_CLIENT + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif +}; + +/* the classes below are for the new LOAD DATA INFILE logging */ + +class Create_file_log_event: public Load_log_event +{ +protected: + // pretend we are Load event, so we can write out just + // our Load part - used on the slave when writing event out to + // SQL_LOAD-*.info file + bool fake_base; +public: + char* block; + uint block_len; + uint file_id; +#ifndef MYSQL_CLIENT + Create_file_log_event(THD* thd, sql_exchange* ex, const char* db_arg, + const char* table_name_arg, + List<Item>& fields_arg, enum enum_duplicates handle_dup, + char* block_arg, uint block_len_arg); +#endif + + Create_file_log_event(const char* buf, int event_len); + ~Create_file_log_event() + { + } + Log_event_type get_type_code() + { + return fake_base ? Load_log_event::get_type_code() : CREATE_FILE_EVENT; + } + int get_data_size() { return fake_base ? Load_log_event::get_data_size() : + Load_log_event::get_data_size() + + 4 + 1 + block_len;} + int get_data_body_offset() { return fake_base ? LOAD_EVENT_OVERHEAD: + LOAD_EVENT_OVERHEAD + CREATE_FILE_HEADER_LEN; } + bool is_valid() { return block != 0; } + int write_data_header(IO_CACHE* file); + int write_data_body(IO_CACHE* file); + int write_base(IO_CACHE* file); // cut out Create_file extentions and + // write it as Load event - used on the slave + +#ifdef MYSQL_CLIENT + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif +}; + +class Append_block_log_event: public Log_event +{ +public: + char* block; + uint block_len; + uint file_id; + +#ifndef MYSQL_CLIENT + Append_block_log_event(THD* thd, char* block_arg, + uint block_len_arg); + int exec_event(struct st_master_info* mi); +#endif + + Append_block_log_event(const char* buf, int event_len); + ~Append_block_log_event() + { + } + Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;} + int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;} + bool is_valid() { return block != 0; } int write_data(IO_CACHE* file); + +#ifdef MYSQL_CLIENT + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + void pack_info(String* packet); +#endif +}; + +class Delete_file_log_event: public Log_event +{ +public: + uint file_id; +#ifndef MYSQL_CLIENT + Delete_file_log_event(THD* thd); +#endif + + Delete_file_log_event(const char* buf, int event_len); + ~Delete_file_log_event() + { + } + Log_event_type get_type_code() { return DELETE_FILE_EVENT;} + int get_data_size() { return DELETE_FILE_HEADER_LEN ;} + bool is_valid() { return file_id != 0; } + int write_data(IO_CACHE* file); + +#ifdef MYSQL_CLIENT + void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif +}; + +class Execute_load_log_event: public Log_event +{ +public: + uint file_id; + +#ifndef MYSQL_CLIENT + Execute_load_log_event(THD* thd); +#endif + + Execute_load_log_event(const char* buf, int event_len); + ~Execute_load_log_event() + { + } + Log_event_type get_type_code() { return EXEC_LOAD_EVENT;} + int get_data_size() { return EXEC_LOAD_HEADER_LEN ;} + bool is_valid() { return file_id != 0; } + int write_data(IO_CACHE* file); + +#ifdef MYSQL_CLIENT void print(FILE* file, bool short_form = 0, char* last_db = 0); +#endif +#ifndef MYSQL_CLIENT + void pack_info(String* packet); + int exec_event(struct st_master_info* mi); +#endif }; + #endif + + + diff --git a/sql/md5.c b/sql/md5.c index 4c2e80107b8..66b96b92ab2 100644 --- a/sql/md5.c +++ b/sql/md5.c @@ -108,7 +108,7 @@ Rotation is separate from addition to prevent recomputation. /* MD5 initialization. Begins an MD5 operation, writing a new context. */ -void MD5Init (MD5_CTX *context) /* context */ +void my_MD5Init (my_MD5_CTX *context) /* context */ { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. @@ -123,8 +123,9 @@ void MD5Init (MD5_CTX *context) /* context */ operation, processing another message block, and updating the context. */ -void MD5Update ( -MD5_CTX *context, /* context */ + +void my_MD5Update ( +my_MD5_CTX *context, /* context */ unsigned char *input, /* input block */ unsigned int inputLen) /* length of input block */ { @@ -164,9 +165,10 @@ unsigned int inputLen) /* length of input block */ /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ -void MD5Final ( + +void my_MD5Final ( unsigned char digest[16], /* message digest */ -MD5_CTX *context) /* context */ +my_MD5_CTX *context) /* context */ { unsigned char bits[8]; unsigned int idx, padLen; @@ -178,10 +180,10 @@ MD5_CTX *context) /* context */ */ idx = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (idx < 56) ? (56 - idx) : (120 - idx); - MD5Update (context, PADDING, padLen); + my_MD5Update (context, PADDING, padLen); /* Append length (before padding) */ - MD5Update (context, bits, 8); + my_MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); diff --git a/sql/md5.h b/sql/md5.h index 862129391f1..6fe4e543bb0 100644 --- a/sql/md5.h +++ b/sql/md5.h @@ -57,22 +57,20 @@ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it #else #define PROTO_LIST(list) () #endif - - /* MD5 context. */ typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; +} my_MD5_CTX; #ifdef __cplusplus extern "C" { #endif - void MD5Init PROTO_LIST ((MD5_CTX *)); - void MD5Update PROTO_LIST - ((MD5_CTX *, unsigned char *, unsigned int)); - void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + void my_MD5Init PROTO_LIST ((my_MD5_CTX *)); + void my_MD5Update PROTO_LIST + ((my_MD5_CTX *, unsigned char *, unsigned int)); + void my_MD5Final PROTO_LIST ((unsigned char [16], my_MD5_CTX *)); #ifdef __cplusplus } diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index cddacaa820f..24af439961e 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -57,6 +57,8 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize, /* There is no file in net_reading */ info->file= file; + info->pre_close = info->pre_read = info->post_read = 0; + info->arg = 0; if (!cachesize) if (! (cachesize= my_default_record_cache_size)) DBUG_RETURN(1); /* No cache requested */ @@ -535,8 +537,13 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) int _my_b_get(IO_CACHE *info) { byte buff; + IO_CACHE_CALLBACK pre_read,post_read; + if ((pre_read = info->pre_read)) + (*pre_read)(info); if ((*(info)->read_function)(info,&buff,1)) return my_b_EOF; + if ((post_read = info->post_read)) + (*post_read)(info); return (int) (uchar) buff; } @@ -675,7 +682,10 @@ int flush_io_cache(IO_CACHE *info) int end_io_cache(IO_CACHE *info) { int error=0; + IO_CACHE_CALLBACK pre_close; DBUG_ENTER("end_io_cache"); + if((pre_close=info->pre_close)) + (*pre_close)(info); if (info->buffer) { if (info->file != -1) /* File doesn't exist */ diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 3dfd58375a5..09944959673 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -41,6 +41,8 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a #endif #include <global.h> +#include <mysql_com.h> +#include <violite.h> #include <my_sys.h> #include <mysys_err.h> #include <m_string.h> @@ -50,7 +52,11 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a #include "mysql_version.h" #include "mysqld_error.h" #include "errmsg.h" -#include <violite.h> + +#ifdef EMBEDDED_LIBRARY +#define net_read_timeout net_read_timeout1 +#define net_write_timeout net_write_timeout1 +#endif #if defined( OS2) && defined( MYSQL_SERVER) #undef ER @@ -90,9 +96,22 @@ extern "C" { // Because of SCO 3.2V4.2 } +static void mc_free_rows(MYSQL_DATA *cur); +static MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, + my_bool long_flag_protocol); + static void mc_end_server(MYSQL *mysql); static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to); static void mc_free_old_query(MYSQL *mysql); +static int mc_send_file_to_server(MYSQL *mysql, const char *filename); +static my_ulonglong mc_net_field_length_ll(uchar **packet); +static ulong mc_net_field_length(uchar **packet); +static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, + ulong *lengths); +static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + uint fields); + #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES) @@ -761,6 +780,20 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, mysql->client_flag=client_flag; #ifdef HAVE_OPENSSL + if ((mysql->server_capabilities & CLIENT_SSL) && + (mysql->options.use_ssl || (client_flag & CLIENT_SSL))) + { + DBUG_PRINT("info", ("Changing IO layer to SSL")); + client_flag |= CLIENT_SSL; + } + else + { + if (client_flag & CLIENT_SSL) + { + DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL")); + } + client_flag &= ~CLIENT_SSL; + } /* Oops.. are we careful enough to not send ANY information */ /* without encryption? */ if (client_flag & CLIENT_SSL) @@ -769,15 +802,14 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, goto error; /* Do the SSL layering. */ DBUG_PRINT("info", ("IO layer change in progress...")); - VioSSLConnectorFd* connector_fd = (VioSSLConnectorFd*) - (mysql->connector_fd); - VioSocket* vio_socket = (VioSocket*)(mysql->net.vio); - VioSSL* vio_ssl = connector_fd->connect(vio_socket); - mysql->net.vio = (NetVio*)(vio_ssl); + DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_)); + sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio); + DBUG_PRINT("info", ("IO layer change done!")); } #endif /* HAVE_OPENSSL */ - int3store(buff+2,max_allowed_packet); + + if (user && user[0]) strmake(buff+5,user,32); else @@ -816,6 +848,32 @@ error: DBUG_RETURN(0); } + +#ifdef HAVE_OPENSSL +/* +************************************************************************** +** Free strings in the SSL structure and clear 'use_ssl' flag. +** NB! Errors are not reported until you do mysql_real_connect. +************************************************************************** +*/ +int STDCALL +mysql_ssl_clear(MYSQL *mysql) +{ + my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); + my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); + mysql->options.ssl_key = 0; + mysql->options.ssl_cert = 0; + mysql->options.ssl_ca = 0; + mysql->options.ssl_capath = 0; + mysql->options.use_ssl = FALSE; + my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR)); + mysql->connector_fd = 0; + return 0; +} +#endif /* HAVE_OPENSSL */ + /************************************************************************* ** Send a QUIT to the server and close the connection ** If handle is alloced by mysql connect free it. @@ -844,11 +902,505 @@ mc_mysql_close(MYSQL *mysql) bzero((char*) &mysql->options,sizeof(mysql->options)); mysql->net.vio = 0; #ifdef HAVE_OPENSSL - ((VioConnectorFd*)(mysql->connector_fd))->delete(); - mysql->connector_fd = 0; + mysql_ssl_clear(mysql); #endif /* HAVE_OPENSSL */ if (mysql->free_me) my_free((gptr) mysql,MYF(0)); } DBUG_VOID_RETURN; } + +void STDCALL mc_mysql_free_result(MYSQL_RES *result) +{ + DBUG_ENTER("mc_mysql_free_result"); + DBUG_PRINT("enter",("mysql_res: %lx",result)); + if (result) + { + if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) + { + DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows")); + for (;;) + { + uint pkt_len; + if ((pkt_len=(uint) mc_net_safe_read(result->handle)) == packet_error) + break; + if (pkt_len == 1 && result->handle->net.read_pos[0] == 254) + break; /* End of data */ + } + result->handle->status=MYSQL_STATUS_READY; + } + mc_free_rows(result->data); + if (result->fields) + free_root(&result->field_alloc,MYF(0)); + if (result->row) + my_free((gptr) result->row,MYF(0)); + my_free((gptr) result,MYF(0)); + } + DBUG_VOID_RETURN; +} + +static void mc_free_rows(MYSQL_DATA *cur) +{ + if (cur) + { + free_root(&cur->alloc,MYF(0)); + my_free((gptr) cur,MYF(0)); + } +} + +static MYSQL_FIELD * +mc_unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, my_bool long_flag_protocol) +{ + MYSQL_ROWS *row; + MYSQL_FIELD *field,*result; + DBUG_ENTER("unpack_fields"); + + field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields); + if (!result) + DBUG_RETURN(0); + + for (row=data->data; row ; row = row->next,field++) + { + field->table= strdup_root(alloc,(char*) row->data[0]); + field->name= strdup_root(alloc,(char*) row->data[1]); + field->length= (uint) uint3korr(row->data[2]); + field->type= (enum enum_field_types) (uchar) row->data[3][0]; + if (long_flag_protocol) + { + field->flags= uint2korr(row->data[4]); + field->decimals=(uint) (uchar) row->data[4][2]; + } + else + { + field->flags= (uint) (uchar) row->data[4][0]; + field->decimals=(uint) (uchar) row->data[4][1]; + } + if (INTERNAL_NUM_FIELD(field)) + field->flags|= NUM_FLAG; + if (default_value && row->data[5]) + field->def=strdup_root(alloc,(char*) row->data[5]); + else + field->def=0; + field->max_length= 0; + } + mc_free_rows(data); /* Free old data */ + DBUG_RETURN(result); +} + +int STDCALL +mc_mysql_send_query(MYSQL* mysql, const char* query, uint length) +{ + return mc_simple_command(mysql, COM_QUERY, query, length, 1); +} + +int STDCALL mc_mysql_read_query_result(MYSQL *mysql) +{ + uchar *pos; + ulong field_count; + MYSQL_DATA *fields; + uint length; + DBUG_ENTER("mc_mysql_read_query_result"); + + if ((length = mc_net_safe_read(mysql)) == packet_error) + DBUG_RETURN(-1); + mc_free_old_query(mysql); /* Free old result */ +get_info: + pos=(uchar*) mysql->net.read_pos; + if ((field_count= mc_net_field_length(&pos)) == 0) + { + mysql->affected_rows= mc_net_field_length_ll(&pos); + mysql->insert_id= mc_net_field_length_ll(&pos); + if (mysql->server_capabilities & CLIENT_TRANSACTIONS) + { + mysql->server_status=uint2korr(pos); pos+=2; + } + if (pos < mysql->net.read_pos+length && mc_net_field_length(&pos)) + mysql->info=(char*) pos; + DBUG_RETURN(0); + } + if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ + { + int error=mc_send_file_to_server(mysql,(char*) pos); + if ((length=mc_net_safe_read(mysql)) == packet_error || error) + DBUG_RETURN(-1); + goto get_info; /* Get info packet */ + } + if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) + mysql->server_status|= SERVER_STATUS_IN_TRANS; + + mysql->extra_info= mc_net_field_length_ll(&pos); /* Maybe number of rec */ + if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5))) + DBUG_RETURN(-1); + if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc, + (uint) field_count,0, + (my_bool) test(mysql->server_capabilities & + CLIENT_LONG_FLAG)))) + DBUG_RETURN(-1); + mysql->status=MYSQL_STATUS_GET_RESULT; + mysql->field_count=field_count; + DBUG_RETURN(0); +} + +int STDCALL mc_mysql_query(MYSQL *mysql, const char *query, uint length) +{ + DBUG_ENTER("mysql_real_query"); + DBUG_PRINT("enter",("handle: %lx",mysql)); + DBUG_PRINT("query",("Query = \"%s\"",query)); + if(!length) + length = strlen(query); + if (mc_simple_command(mysql,COM_QUERY,query,length,1)) + DBUG_RETURN(-1); + DBUG_RETURN(mc_mysql_read_query_result(mysql)); +} + +static int mc_send_file_to_server(MYSQL *mysql, const char *filename) +{ + int fd, readcount; + char buf[IO_SIZE*15],*tmp_name; + DBUG_ENTER("send_file_to_server"); + + fn_format(buf,filename,"","",4); /* Convert to client format */ + if (!(tmp_name=my_strdup(buf,MYF(0)))) + { + strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY)); + DBUG_RETURN(-1); + } + if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0) + { + mysql->net.last_errno=EE_FILENOTFOUND; + sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno); + strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1); + my_net_write(&mysql->net,"",0); net_flush(&mysql->net); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + + while ((readcount = (int) my_read(fd,buf,sizeof(buf),MYF(0))) > 0) + { + if (my_net_write(&mysql->net,buf,readcount)) + { + mysql->net.last_errno=CR_SERVER_LOST; + strmov(mysql->net.last_error,ER(mysql->net.last_errno)); + DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file")); + (void) my_close(fd,MYF(0)); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + } + (void) my_close(fd,MYF(0)); + /* Send empty packet to mark end of file */ + if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net)) + { + mysql->net.last_errno=CR_SERVER_LOST; + sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + if (readcount < 0) + { + mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */ + sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno); + strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1); + my_free(tmp_name,MYF(0)); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + +/* Get the length of next field. Change parameter to point at fieldstart */ +static ulong mc_net_field_length(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (ulong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (ulong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (ulong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ + return (ulong) uint4korr(pos+1); +} + +/* Same as above, but returns ulonglong values */ + +static my_ulonglong mc_net_field_length_ll(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (my_ulonglong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return (my_ulonglong) NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (my_ulonglong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (my_ulonglong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ +#ifdef NO_CLIENT_LONGLONG + return (my_ulonglong) uint4korr(pos+1); +#else + return (my_ulonglong) uint8korr(pos+1); +#endif +} + +/* Read all rows (fields or data) from server */ + +static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + uint fields) +{ + uint field,pkt_len; + ulong len; + uchar *cp; + char *to; + MYSQL_DATA *result; + MYSQL_ROWS **prev_ptr,*cur; + NET *net = &mysql->net; + DBUG_ENTER("mc_read_rows"); + + if ((pkt_len=(uint) mc_net_safe_read(mysql)) == packet_error) + DBUG_RETURN(0); + if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), + MYF(MY_WME | MY_ZEROFILL)))) + { + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ + result->alloc.min_malloc=sizeof(MYSQL_ROWS); + prev_ptr= &result->data; + result->rows=0; + result->fields=fields; + + while (*(cp=net->read_pos) != 254 || pkt_len != 1) + { + result->rows++; + if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, + sizeof(MYSQL_ROWS))) || + !(cur->data= ((MYSQL_ROW) + alloc_root(&result->alloc, + (fields+1)*sizeof(char *)+pkt_len)))) + { + mc_free_rows(result); + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + *prev_ptr=cur; + prev_ptr= &cur->next; + to= (char*) (cur->data+fields+1); + for (field=0 ; field < fields ; field++) + { + if ((len=(ulong) mc_net_field_length(&cp)) == NULL_LENGTH) + { /* null field */ + cur->data[field] = 0; + } + else + { + cur->data[field] = to; + memcpy(to,(char*) cp,len); to[len]=0; + to+=len+1; + cp+=len; + if (mysql_fields) + { + if (mysql_fields[field].max_length < len) + mysql_fields[field].max_length=len; + } + } + } + cur->data[field]=to; /* End of last field */ + if ((pkt_len=mc_net_safe_read(mysql)) == packet_error) + { + mc_free_rows(result); + DBUG_RETURN(0); + } + } + *prev_ptr=0; /* last pointer is null */ + DBUG_PRINT("exit",("Got %d rows",result->rows)); + DBUG_RETURN(result); +} + + +/* +** Read one row. Uses packet buffer as storage for fields. +** When next packet is read, the previous field values are destroyed +*/ + + +static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, + ulong *lengths) +{ + uint field; + ulong pkt_len,len; + uchar *pos,*prev_pos; + + if ((pkt_len=(uint) mc_net_safe_read(mysql)) == packet_error) + return -1; + if (pkt_len == 1 && mysql->net.read_pos[0] == 254) + return 1; /* End of data */ + prev_pos= 0; /* allowed to write at packet[-1] */ + pos=mysql->net.read_pos; + for (field=0 ; field < fields ; field++) + { + if ((len=(ulong) mc_net_field_length(&pos)) == NULL_LENGTH) + { /* null field */ + row[field] = 0; + *lengths++=0; + } + else + { + row[field] = (char*) pos; + pos+=len; + *lengths++=len; + } + if (prev_pos) + *prev_pos=0; /* Terminate prev field */ + prev_pos=pos; + } + row[field]=(char*) prev_pos+1; /* End of last field */ + *prev_pos=0; /* Terminate last field */ + return 0; +} + +my_ulonglong STDCALL mc_mysql_num_rows(MYSQL_RES *res) +{ + return res->row_count; +} + +unsigned int STDCALL mc_mysql_num_fields(MYSQL_RES *res) +{ + return res->field_count; +} + +void STDCALL mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row) +{ + MYSQL_ROWS *tmp=0; + DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row)); + if (result->data) + for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ; + result->current_row=0; + result->data_cursor = tmp; +} + +MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res) +{ + DBUG_ENTER("mc_mysql_fetch_row"); + if (!res->data) + { /* Unbufferred fetch */ + if (!res->eof) + { + if (!(mc_read_one_row(res->handle,res->field_count,res->row, + res->lengths))) + { + res->row_count++; + DBUG_RETURN(res->current_row=res->row); + } + else + { + DBUG_PRINT("info",("end of data")); + res->eof=1; + res->handle->status=MYSQL_STATUS_READY; + } + } + DBUG_RETURN((MYSQL_ROW) NULL); + } + { + MYSQL_ROW tmp; + if (!res->data_cursor) + { + DBUG_PRINT("info",("end of data")); + DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL); + } + tmp = res->data_cursor->data; + res->data_cursor = res->data_cursor->next; + DBUG_RETURN(res->current_row=tmp); + } +} + +int STDCALL mc_mysql_select_db(MYSQL *mysql, const char *db) +{ + int error; + DBUG_ENTER("mysql_select_db"); + DBUG_PRINT("enter",("db: '%s'",db)); + + if ((error=mc_simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0))) + DBUG_RETURN(error); + my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); + mysql->db=my_strdup(db,MYF(MY_WME)); + DBUG_RETURN(0); +} + + +MYSQL_RES * STDCALL mc_mysql_store_result(MYSQL *mysql) +{ + MYSQL_RES *result; + DBUG_ENTER("mysql_store_result"); + + if (!mysql->fields) + DBUG_RETURN(0); + if (mysql->status != MYSQL_STATUS_GET_RESULT) + { + strmov(mysql->net.last_error, + ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + DBUG_RETURN(0); + } + mysql->status=MYSQL_STATUS_READY; /* server is ready */ + if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+ + sizeof(ulong)*mysql->field_count, + MYF(MY_WME | MY_ZEROFILL)))) + { + mysql->net.last_errno=CR_OUT_OF_MEMORY; + strmov(mysql->net.last_error, ER(mysql->net.last_errno)); + DBUG_RETURN(0); + } + result->eof=1; /* Marker for buffered */ + result->lengths=(ulong*) (result+1); + if (!(result->data=mc_read_rows(mysql,mysql->fields,mysql->field_count))) + { + my_free((gptr) result,MYF(0)); + DBUG_RETURN(0); + } + mysql->affected_rows= result->row_count= result->data->rows; + result->data_cursor= result->data->data; + result->fields= mysql->fields; + result->field_alloc= mysql->field_alloc; + result->field_count= mysql->field_count; + result->current_field=0; + result->current_row=0; /* Must do a fetch first */ + mysql->fields=0; /* fields is now in result */ + DBUG_RETURN(result); /* Data fetched */ +} + + + + + + + + diff --git a/sql/mini_client.h b/sql/mini_client.h index f7d95a1b66e..22cdb31f846 100644 --- a/sql/mini_client.h +++ b/sql/mini_client.h @@ -42,6 +42,17 @@ char * STDCALL mc_mysql_error(MYSQL *mysql); int STDCALL mc_mysql_errno(MYSQL *mysql); my_bool STDCALL mc_mysql_reconnect(MYSQL* mysql); +int STDCALL mc_mysql_send_query(MYSQL* mysql, const char* query, uint length); +int STDCALL mc_mysql_read_query_result(MYSQL *mysql); +int STDCALL mc_mysql_query(MYSQL *mysql, const char *query, uint length); +MYSQL_RES * STDCALL mc_mysql_store_result(MYSQL *mysql); +void STDCALL mc_mysql_free_result(MYSQL_RES *result); +void STDCALL mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row); +my_ulonglong STDCALL mc_mysql_num_rows(MYSQL_RES *res); +unsigned int STDCALL mc_mysql_num_fields(MYSQL_RES *res); +MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res); +int STDCALL mc_mysql_select_db(MYSQL *mysql, const char *db); + #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 841d76928e1..8e38c8174a4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -26,7 +26,6 @@ #include <thr_lock.h> #include <my_base.h> /* Needed by field.h */ #include <my_bitmap.h> -#include <violite.h> #ifdef __EMX__ #undef write // remove pthread.h macro definition for EMX @@ -37,6 +36,7 @@ typedef ulong key_map; /* Used for finding keys */ typedef ulong key_part_map; /* Used for finding key parts */ #include "mysql_com.h" +#include <violite.h> #include "unireg.h" void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size); @@ -47,6 +47,7 @@ char *sql_strmake(const char *str,uint len); gptr sql_memdup(const void * ptr,unsigned size); void sql_element_free(void *ptr); void kill_one_thread(THD *thd, ulong id); +char* query_table_status(THD *thd,const char *db,const char *table_name); #define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); } #define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } } @@ -147,9 +148,9 @@ void kill_one_thread(THD *thd, ulong id); #define SELECT_DESCRIBE 4 #define SELECT_SMALL_RESULT 8 #define SELECT_BIG_RESULT 16 +#define OPTION_FOUND_ROWS 32 #define SELECT_HIGH_PRIORITY 64 /* Intern */ -#define SELECT_USE_CACHE 256 /* Intern */ -#define SELECT_COUNT_DISTINCT 512 /* Intern */ +#define SELECT_NO_JOIN_CACHE 256 /* Intern */ #define OPTION_BIG_TABLES 512 /* for SQL OPTION */ #define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */ @@ -158,7 +159,8 @@ void kill_one_thread(THD *thd, ulong id); #define OPTION_LOW_PRIORITY_UPDATES 8192 #define OPTION_WARNINGS 16384 #define OPTION_AUTO_IS_NULL 32768 -#define OPTION_SAFE_UPDATES 65536L*2 +#define OPTION_ANSI_MODE 65536L +#define OPTION_SAFE_UPDATES OPTION_ANSI_MODE*2 #define OPTION_BUFFER_RESULT OPTION_SAFE_UPDATES*2 #define OPTION_BIN_LOG OPTION_BUFFER_RESULT*2 #define OPTION_NOT_AUTO_COMMIT OPTION_BIN_LOG*2 @@ -175,7 +177,9 @@ void kill_one_thread(THD *thd, ulong id); #define QUERY_NO_INDEX_USED OPTION_STATUS_NO_TRANS_UPDATE*2 #define QUERY_NO_GOOD_INDEX_USED QUERY_NO_INDEX_USED*2 -/* Bits for different SQL modes modes (including ANSI mode) */ +#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2) +#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2) + #define MODE_REAL_AS_FLOAT 1 #define MODE_PIPES_AS_CONCAT 2 #define MODE_ANSI_QUOTES 4 @@ -233,15 +237,18 @@ inline THD *_current_thd(void) #include "opt_range.h" -void mysql_create_db(THD *thd, char *db, uint create_info); +int mysql_create_db(THD *thd, char *db, uint create_info); void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags); int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists); +int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, + bool log_query); int quick_rm_table(enum db_type base,const char *db, const char *table_name); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); void mysql_init_select(LEX *lex); +void mysql_new_select(LEX *lex); void init_max_user_conn(void); void free_max_user_conn(void); pthread_handler_decl(handle_one_connection,arg); @@ -251,9 +258,11 @@ void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); void mysql_execute_command(void); bool do_command(THD *thd); +bool dispatch_command(enum enum_server_command command, THD *thd, + char* packet, uint packet_length); bool check_stack_overrun(THD *thd,char *dummy); bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables); -void mysql_rm_db(THD *thd,char *db,bool if_exists); +int mysql_rm_db(THD *thd,char *db,bool if_exists); void table_cache_init(void); void table_cache_free(void); uint cached_tables(void); @@ -261,13 +270,9 @@ void kill_mysql(void); void close_connection(NET *net,uint errcode=0,bool lock=1); bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0, bool no_grant=0); -bool check_table_access(THD *thd,uint want_access,TABLE_LIST *tables); +bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables); bool check_process_priv(THD *thd=0); -int generate_table(THD *thd, TABLE_LIST *table_list, - TABLE *locked_table); - - int mysql_backup_table(THD* thd, TABLE_LIST* table_list); int mysql_restore_table(THD* thd, TABLE_LIST* table_list); @@ -281,7 +286,6 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); /* net_pkg.c */ -void send_error(NET *net,uint sql_errno=0, const char *err=0); void send_warning(NET *net, uint sql_errno, const char *err=0); void net_printf(NET *net,uint sql_errno, ...); void send_ok(NET *net,ha_rows affected_rows=0L,ulonglong id=0L, @@ -308,10 +312,12 @@ SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields, List <Item> &all_fields, ORDER *order); +int handle_select(THD *thd, LEX *lex, select_result *result); int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds, List<Item_func_match> &ftfuncs, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - uint select_type,select_result *result); + ulong select_type,select_result *result); +int mysql_union(THD *thd,LEX *lex,select_result *result); Field *create_tmp_field(TABLE *table,Item *item, Item::Type type, Item_result_field ***copy_func, Field **from_field, bool group,bool modify_item); @@ -336,7 +342,9 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name, List<Alter_column> &alter_list, ORDER *order, bool drop_primary, - enum enum_duplicates handle_duplicates); + enum enum_duplicates handle_duplicates, + enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS, + bool simple_alter=0); bool mysql_rename_table(enum db_type base, const char *old_db, const char * old_name, @@ -347,15 +355,17 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys); int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop_list); int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &values,COND *conds, ha_rows limit, + List<Item> &values,COND *conds, + ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates, thr_lock_type lock_type); int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, List<List_item> &values, enum_duplicates flag, thr_lock_type lock_type); void kill_delayed_threads(void); -int mysql_delete(THD *thd,TABLE_LIST *table,COND *conds,ha_rows rows, - thr_lock_type lock_type, ulong options); +int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order, + ha_rows rows, thr_lock_type lock_type, ulong options); +int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias, bool *refresh); @@ -376,7 +386,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, /* sql_list.c */ int mysqld_show_dbs(THD *thd,const char *wild); -int mysqld_show_open_tables(THD *thd,const char *db,const char *wild); +int mysqld_show_open_tables(THD *thd,const char *wild); int mysqld_show_tables(THD *thd,const char *db,const char *wild); int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild); int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild, @@ -392,6 +402,12 @@ int mysqld_show_status(THD *thd); int mysqld_show_variables(THD *thd,const char *wild); int mysqld_show(THD *thd, const char *wild, show_var_st *variables); +/* sql_handler.cc */ +int mysql_ha_open(THD *thd, TABLE_LIST *tables); +int mysql_ha_close(THD *thd, TABLE_LIST *tables); +int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, + List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); + /* sql_base.cc */ void set_item_name(Item *item,char *pos,uint length); bool add_field_to_list(char *field_name, enum enum_field_types type, @@ -413,9 +429,13 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, int *error); Item ** find_item_in_list(Item *item,List<Item> &items); +bool insert_fields(THD *thd,TABLE_LIST *tables, + const char *db_name, const char *table_name, + List_iterator<Item> *it); bool setup_tables(TABLE_LIST *tables); int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item, - bool set_query_id,List<Item> *sum_func_list); + bool set_query_id,List<Item> *sum_func_list, + bool allow_sum_func); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs); void wait_for_refresh(THD *thd); @@ -429,6 +449,7 @@ bool send_fields(THD *thd,List<Item> &item,uint send_field_count); void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); void close_thread_tables(THD *thd,bool locked=0); +bool close_thread_table(THD *thd, TABLE **table_ptr); void close_temporary_tables(THD *thd); TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name); bool close_temporary_table(THD *thd, const char *db, const char *table_name); @@ -443,8 +464,7 @@ bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables); void copy_field_from_tmp_record(Field *field,int offset); int fill_record(List<Item> &fields,List<Item> &values); int fill_record(Field **field,List<Item> &values); -int list_open_tables(THD *thd,List<char> *files, const char *db,const char *wild); -char* query_table_status(THD *thd,const char *db,const char *table_name); +OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); /* sql_calc.cc */ bool eval_const_cond(COND *cond); @@ -469,8 +489,7 @@ pthread_handler_decl(handle_manager, arg); #ifndef DBUG_OFF void print_where(COND *cond,const char *info); void print_cached_tables(void); -void TEST_filesort(TABLE **form,SORT_FIELD *sortorder,uint s_length, - ha_rows special); +void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special); #endif void mysql_print_status(THD *thd); /* key.cc */ @@ -516,7 +535,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status, LOCK_grant, LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, - LOCK_binlog_update, LOCK_slave, LOCK_server_id; + LOCK_binlog_update, LOCK_slave, LOCK_server_id, LOCK_slave_list; extern pthread_cond_t COND_refresh,COND_thread_count, COND_binlog_update, COND_slave_stopped, COND_slave_start; extern pthread_attr_t connection_attrib; @@ -538,13 +557,14 @@ extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size, max_insert_delayed_threads, max_user_connections, long_query_count,net_wait_timeout,net_interactive_timeout, net_read_timeout,net_write_timeout, - what_to_log,flush_time, opt_sql_mode, + what_to_log,flush_time,opt_sql_mode, max_tmp_tables,max_heap_table_size,query_buff_size, lower_case_table_names,thread_stack,thread_stack_min, - binlog_cache_size, max_binlog_cache_size, record_rnd_cache_size; + binlog_cache_size, max_binlog_cache_size,record_rnd_cache_size; extern ulong specialflag, current_pid; -extern bool low_priority_updates, using_update_log,opt_warnings; -extern bool opt_sql_bin_update, opt_safe_show_db, opt_safe_user_create; +extern bool low_priority_updates, using_update_log; +extern bool opt_sql_bin_update, opt_safe_show_db, opt_warnings, + opt_safe_user_create, opt_no_mix_types; extern char language[LIBLEN],reg_ext[FN_EXTLEN],blob_newline; extern const char **errmesg; /* Error messages */ extern const char *default_tx_isolation_name; @@ -568,8 +588,13 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); +bool lock_global_read_lock(THD *thd); +void unlock_global_read_lock(THD *thd); +bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh); +void start_waiting_global_read_lock(THD *thd); /* Lock based on name */ +int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); int lock_table_name(THD *thd, TABLE_LIST *table_list); void unlock_table_name(THD *thd, TABLE_LIST *table_list); bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list); @@ -612,7 +637,7 @@ void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors); void end_read_record(READ_RECORD *info); -ha_rows filesort(TABLE **form,struct st_sort_field *sortorder, uint s_length, +ha_rows filesort(TABLE *form,struct st_sort_field *sortorder, uint s_length, SQL_SELECT *select, ha_rows special,ha_rows max_rows, ha_rows *examined_rows); void change_double_for_sort(double nr,byte *to); @@ -663,7 +688,7 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length); inline bool add_item_to_list(Item *item) { - return current_lex->item_list.push_back(item); + return current_lex->select->item_list.push_back(item); } inline bool add_value_to_list(Item *value) { @@ -671,11 +696,11 @@ inline bool add_value_to_list(Item *value) } inline bool add_order_to_list(Item *item,bool asc) { - return add_to_list(current_lex->order_list,item,asc); + return add_to_list(current_lex->select->order_list,item,asc); } inline bool add_group_to_list(Item *item,bool asc) { - return add_to_list(current_lex->group_list,item,asc); + return add_to_list(current_lex->select->group_list,item,asc); } inline void mark_as_null_row(TABLE *table) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9aa56ea7fc1..20ccb6d1f76 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -40,6 +40,13 @@ #define ONE_THREAD #endif +/* do stack traces are only supported on linux intel */ +#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK) +#define HAVE_STACK_TRACE_ON_SEGV +#include "../pstack/pstack.h" +char pstack_file_name[80]; +#endif /* __linux__ */ + extern "C" { // Because of SCO 3.2V4.2 #include <errno.h> #include <sys/stat.h> @@ -197,13 +204,15 @@ SHOW_COMP_OPTION have_raid=SHOW_OPTION_YES; SHOW_COMP_OPTION have_raid=SHOW_OPTION_NO; #endif #ifdef HAVE_OPENSSL -SHOW_COMP_OPTION have_ssl=SHOW_OPTION_YES; +SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES; #else -SHOW_COMP_OPTION have_ssl=SHOW_OPTION_NO; +SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO; #endif +SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES; static bool opt_skip_slave_start = 0; // if set, slave is not autostarted +static bool opt_do_pstack = 0; static ulong opt_specialflag=SPECIAL_ENGLISH; static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET; static ulong back_log,connect_timeout,concurrency; @@ -216,7 +225,8 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl, opt_myisam_log=0, opt_large_files=sizeof(my_off_t) > 4; bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0, - opt_safe_user_create=0; + opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0, + opt_safe_user_create = 0, opt_no_mix_types = 0; FILE *bootstrap_file=0; int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice extern MASTER_INFO glob_mi; @@ -238,7 +248,7 @@ static char *opt_ssl_key = 0; static char *opt_ssl_cert = 0; static char *opt_ssl_ca = 0; static char *opt_ssl_capath = 0; -static VioSSLAcceptorFd* ssl_acceptor_fd = 0; +struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0; #endif /* HAVE_OPENSSL */ @@ -252,9 +262,9 @@ uint32 server_id = 0; bool server_id_supplied = 0; uint mysql_port; -uint test_flags, select_errors=0, dropping_tables=0,ha_open_options=0; +uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0; uint volatile thread_count=0, thread_running=0, kill_cached_threads=0, - wake_thread=0, global_read_lock=0; + wake_thread=0; ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE ); uint protocol_version=PROTOCOL_VERSION; @@ -271,10 +281,14 @@ volatile ulong cached_thread_count=0; // replication parameters, if master_host is not NULL, we are a slave my_string master_user = (char*) "test", master_password = 0, master_host=0, - master_info_file = (char*) "master.info"; + master_info_file = (char*) "master.info", master_ssl_key=0, master_ssl_cert=0; +my_string report_user = 0, report_password = 0, report_host=0; + const char *localhost=LOCAL_HOST; const char *delayed_user="DELAYED"; uint master_port = MYSQL_PORT, master_connect_retry = 60; +uint report_port = MYSQL_PORT; +bool master_ssl = 0; ulong max_tmp_tables,max_heap_table_size; ulong bytes_sent = 0L, bytes_received = 0L; @@ -343,7 +357,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_binlog_update, LOCK_slave, LOCK_server_id, - LOCK_user_conn; + LOCK_user_conn, LOCK_slave_list; pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update, COND_slave_stopped, COND_slave_start; @@ -528,7 +542,7 @@ static void close_connections(void) /* Force remaining threads to die by closing the connection to the client */ - (void) my_net_init(&net, (Vio*) 0); + (void) my_net_init(&net, (st_vio*) 0); for (;;) { DBUG_PRINT("quit",("Locking LOCK_thread_count")); @@ -587,16 +601,16 @@ void kill_mysql(void) #elif defined(OS2) pthread_cond_signal( &eventShutdown); // post semaphore #elif defined(HAVE_PTHREAD_KILL) - if (pthread_kill(signal_thread,MYSQL_KILL_SIGNAL))// End everything nicely - { - DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */ - } + if (pthread_kill(signal_thread,SIGTERM)) /* End everything nicely */ + { + DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */ + } #else - kill(current_pid,MYSQL_KILL_SIGNAL); + kill(current_pid,SIGTERM); #endif - DBUG_PRINT("quit",("After pthread_kill")); - shutdown_in_progress=1; // Safety if kill didn't work - DBUG_VOID_RETURN; + DBUG_PRINT("quit",("After pthread_kill")); + shutdown_in_progress=1; // Safety if kill didn't work + DBUG_VOID_RETURN; } @@ -702,12 +716,22 @@ void clean_up(bool print_message) #ifdef USE_RAID end_raid(); #endif +#ifdef HAVE_OPENSSL + my_free(opt_ssl_key,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_ssl_cert,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_ssl_ca,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_ssl_capath,MYF(MY_ALLOW_ZERO_PTR)); + opt_ssl_key=opt_ssl_cert=opt_ssl_ca=opt_ssl_capath=0; +#endif /* HAVE_OPENSSL */ free_defaults(defaults_argv); my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql_tmpdir,MYF(0)); + my_free(slave_load_tmpdir,MYF(0)); x_free(opt_bin_logname); bitmap_free(&temp_pool); free_max_user_conn(); + end_slave_list(); + #ifndef __WIN__ if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist @@ -974,7 +998,7 @@ void yyerror(const char *s) void close_connection(NET *net,uint errcode,bool lock) { - Vio* vio; + st_vio* vio; DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("fd: %s error: '%s'", net->vio? vio_description(net->vio):"(not connected)", @@ -1279,8 +1303,8 @@ static void init_signals(void) sigaddset(&set,SIGQUIT); sigaddset(&set,SIGTERM); sigaddset(&set,SIGHUP); - sigset(SIGTERM,print_signal_warning); // If it's blocked by parent - signal(SIGHUP,print_signal_warning); // If it's blocked by parent + signal(SIGTERM,SIG_DFL); // If it's blocked by parent + signal(SIGHUP,SIG_DFL); // If it's blocked by parent #ifdef SIGTSTP sigaddset(&set,SIGTSTP); #endif @@ -1364,6 +1388,13 @@ static void *signal_hand(void *arg __attribute__((unused))) (void) my_close(pidFile,MYF(0)); } } +#ifdef HAVE_STACK_TRACE_ON_SEGV + if (opt_do_pstack) + { + sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid()); + pstack_install_segv_action(pstack_file_name); + } +#endif /* HAVE_STACK_TRACE_ON_SEGV */ // signal to start_signal_handler that we are ready (void) pthread_mutex_lock(&LOCK_thread_count); @@ -1375,7 +1406,7 @@ static void *signal_hand(void *arg __attribute__((unused))) int error; // Used when debugging if (shutdown_in_progress && !abort_loop) { - sig= MYSQL_KILL_SIGNAL; + sig=SIGTERM; error=0; } else @@ -1398,7 +1429,7 @@ static void *signal_hand(void *arg __attribute__((unused))) if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR); if (pthread_create(&tmp,&connection_attrib, kill_server_thread, - (void*) 0)) + (void*) sig)) sql_print_error("Error: Can't create thread to kill server"); #else kill_server((void*) sig); // MIT THREAD has a alarm thread @@ -1406,7 +1437,10 @@ static void *signal_hand(void *arg __attribute__((unused))) } break; case SIGHUP: - reload_acl_and_cache((THD*) 0,REFRESH_LOG, + reload_acl_and_cache((THD*) 0, + (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | + REFRESH_STATUS | REFRESH_GRANT | REFRESH_THREADS | + REFRESH_HOSTS), (TABLE_LIST*) 0); // Flush logs mysql_print_status((THD*) 0); // Send debug some info break; @@ -1673,8 +1707,9 @@ int main(int argc, char **argv) #ifdef HAVE_OPENSSL if (opt_use_ssl) { - ssl_acceptor_fd = VioSSLAcceptorFd_new(opt_ssl_key, opt_ssl_cert, + ssl_acceptor_fd = new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath); + DBUG_PRINT("info",("ssl_acceptor_fd: %p",ssl_acceptor_fd)); if (!ssl_acceptor_fd) opt_use_ssl=0; /* having ssl_acceptor_fd!=0 signals the use of SSL */ @@ -1747,7 +1782,8 @@ int main(int argc, char **argv) randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); init_thr_lock(); - + init_slave_list(); + /* Fix varibles that are base 1024*1024 */ myisam_max_temp_length= (my_off_t) min(((ulonglong) myisam_max_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE); myisam_max_extra_temp_length= (my_off_t) min(((ulonglong) myisam_max_extra_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE); @@ -1810,7 +1846,7 @@ The server will not act as a slave."); LOG_BIN); using_update_log=1; } - + if (opt_slow_log) open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log", LOG_NORMAL); @@ -1832,7 +1868,7 @@ The server will not act as a slave."); } #else locked_in_memory=0; -#endif +#endif if (opt_myisam_log) (void) mi_log( 1 ); @@ -1981,7 +2017,7 @@ The server will not act as a slave."); } #else handle_connections_sockets(0); -#ifdef EXTRA_DEBUG +#ifdef EXTRA_DEBUG2 sql_print_error("Exiting main thread"); #endif #endif /* __NT__ */ @@ -1991,14 +2027,14 @@ The server will not act as a slave."); DBUG_PRINT("quit",("Exiting main thread")); #ifndef __WIN__ -#ifdef EXTRA_DEBUG +#ifdef EXTRA_DEBUG2 sql_print_error("Before Lock_thread_count"); #endif (void) pthread_mutex_lock(&LOCK_thread_count); select_thread_in_use=0; // For close_connections (void) pthread_cond_broadcast(&COND_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); -#ifdef EXTRA_DEBUG +#ifdef EXTRA_DEBUG2 sql_print_error("After lock_thread_count"); #endif #else @@ -2021,7 +2057,9 @@ The server will not act as a slave."); if(hEventShutdown) CloseHandle(hEventShutdown); } #endif - +#ifdef HAVE_OPENSSL + my_free((gptr)ssl_acceptor_fd,MYF(0)); +#endif /* HAVE_OPENSSL */ /* Wait until cleanup is done */ (void) pthread_mutex_lock(&LOCK_thread_count); while (!ready_to_exit) @@ -2097,7 +2135,7 @@ static int bootstrap(FILE *file) int error; thd->bootstrap=1; thd->client_capabilities=0; - my_net_init(&thd->net,(Vio*) 0); + my_net_init(&thd->net,(st_vio*) 0); thd->max_packet_length=thd->net.max_packet; thd->master_access= ~0; thd->thread_id=thread_id++; @@ -2235,7 +2273,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused))) THD *thd; struct sockaddr_in cAddr; int ip_flags=0,socket_flags=0,flags; - Vio *vio_tmp; + st_vio *vio_tmp; DBUG_ENTER("handle_connections_sockets"); LINT_INIT(new_sock); @@ -2534,6 +2572,10 @@ enum options { OPT_MASTER_HOST, OPT_MASTER_USER, OPT_MASTER_PASSWORD, OPT_MASTER_PORT, OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY, +#ifdef HAVE_OPENSSL + OPT_MASTER_SSL, OPT_MASTER_SSL_KEY, + OPT_MASTER_SSL_CERT, +#endif /* HAVE_OPESSSL*/ OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB, OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES, OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB, @@ -2552,16 +2594,18 @@ enum options { OPT_INNODB_LOG_ARCH_DIR, OPT_INNODB_LOG_ARCHIVE, OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT, - OPT_INNODB_UNIX_FILE_FLUSH_METHOD, + OPT_INNODB_FLUSH_METHOD, OPT_SAFE_SHOW_DB, OPT_GEMINI_SKIP, OPT_INNODB_SKIP, - OPT_TEMP_POOL, OPT_TX_ISOLATION, + OPT_TEMP_POOL, OPT_DO_PSTACK, OPT_TX_ISOLATION, OPT_GEMINI_FLUSH_LOG, OPT_GEMINI_RECOVER, OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC, - OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, - OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, - OPT_SAFE_USER_CREATE, OPT_SQL_MODE -}; + OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINK, OPT_REPORT_HOST, + OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT, + OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, + OPT_SHOW_SLAVE_AUTH_INFO, OPT_OLD_RPL_COMPAT, + OPT_SQL_MODE,OPT_SAFE_USER_CREATE, + OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE}; static struct option long_options[] = { {"ansi", no_argument, 0, 'a'}, @@ -2592,6 +2636,8 @@ static struct option long_options[] = { {"default-table-type", required_argument, 0, (int) OPT_TABLE_TYPE}, {"delay-key-write-for-all-tables", no_argument, 0, (int) OPT_DELAY_KEY_WRITE}, + {"do-pstack", + no_argument, 0, (int) OPT_DO_PSTACK}, {"enable-locking", no_argument, 0, (int) OPT_ENABLE_LOCK}, {"exit-info", optional_argument, 0, 'T'}, {"flush", no_argument, 0, (int) OPT_FLUSH}, @@ -2616,7 +2662,7 @@ static struct option long_options[] = { {"innodb_flush_log_at_trx_commit", optional_argument, 0, OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT}, {"innodb_flush_method", required_argument, 0, - OPT_INNODB_UNIX_FILE_FLUSH_METHOD}, + OPT_INNODB_FLUSH_METHOD}, #endif {"help", no_argument, 0, '?'}, {"init-file", required_argument, 0, (int) OPT_INIT_FILE}, @@ -2636,6 +2682,11 @@ static struct option long_options[] = { {"master-port", required_argument, 0, (int) OPT_MASTER_PORT}, {"master-connect-retry", required_argument, 0, (int) OPT_MASTER_CONNECT_RETRY}, {"master-info-file", required_argument, 0, (int) OPT_MASTER_INFO_FILE}, +#ifdef HAVE_OPENSSL + {"master-ssl", optional_argument, 0, (int) OPT_MASTER_SSL}, + {"master-ssl-key", optional_argument, 0, (int) OPT_MASTER_SSL_KEY}, + {"master-ssl-cert", optional_argument, 0, (int) OPT_MASTER_SSL_CERT}, +#endif {"myisam-recover", optional_argument, 0, (int) OPT_MYISAM_RECOVER}, {"memlock", no_argument, 0, (int) OPT_MEMLOCK}, // needs to be available for the test case to pass in non-debugging mode @@ -2651,7 +2702,11 @@ static struct option long_options[] = { {"safemalloc-mem-limit", required_argument, 0, (int) OPT_SAFEMALLOC_MEM_LIMIT}, {"new", no_argument, 0, 'n'}, +#ifdef NOT_YET + {"no-mix-table-types", no_argument, 0, (int)OPT_NO_MIX_TYPE}, +#endif {"old-protocol", no_argument, 0, 'o'}, + {"old-rpl-compat", no_argument, 0, (int)OPT_OLD_RPL_COMPAT}, #ifdef ONE_THREAD {"one-thread", no_argument, 0, (int) OPT_ONE_THREAD}, #endif @@ -2670,11 +2725,19 @@ static struct option long_options[] = { (int) OPT_REPLICATE_WILD_IGNORE_TABLE}, {"replicate-rewrite-db", required_argument, 0, (int) OPT_REPLICATE_REWRITE_DB}, + // In replication, we may need to tell the other servers how to connect + // to us + {"report-host", required_argument, 0, (int) OPT_REPORT_HOST}, + {"report-user", required_argument, 0, (int) OPT_REPORT_USER}, + {"report-password", required_argument, 0, (int) OPT_REPORT_PASSWORD}, + {"report-port", required_argument, 0, (int) OPT_REPORT_PORT}, {"safe-mode", no_argument, 0, (int) OPT_SAFE}, {"safe-show-database", no_argument, 0, (int) OPT_SAFE_SHOW_DB}, - {"safe-user-create", no_argument, 0, (int) OPT_SAFE_USER_CREATE}, + {"socket", required_argument, 0, (int) OPT_SOCKET}, {"server-id", required_argument, 0, (int) OPT_SERVER_ID}, {"set-variable", required_argument, 0, 'O'}, + {"show-slave-auth-info", no_argument, 0, + (int) OPT_SHOW_SLAVE_AUTH_INFO}, {"skip-bdb", no_argument, 0, (int) OPT_BDB_SKIP}, {"skip-innodb", no_argument, 0, (int) OPT_INNODB_SKIP}, {"skip-gemini", no_argument, 0, (int) OPT_GEMINI_SKIP}, @@ -2690,9 +2753,9 @@ static struct option long_options[] = { {"skip-show-database", no_argument, 0, (int) OPT_SKIP_SHOW_DB}, {"skip-slave-start", no_argument, 0, (int) OPT_SKIP_SLAVE_START}, {"skip-stack-trace", no_argument, 0, (int) OPT_SKIP_STACK_TRACE}, - {"skip-symlink", no_argument, 0, (int) OPT_SKIP_SYMLINKS}, + {"skip-symlink", no_argument, 0, (int) OPT_SKIP_SYMLINK}, {"skip-thread-priority", no_argument, 0, (int) OPT_SKIP_PRIOR}, - {"socket", required_argument, 0, (int) OPT_SOCKET}, + {"slave-load-tmpdir", required_argument, 0, (int) OPT_SLAVE_LOAD_TMPDIR}, {"sql-bin-update-same", no_argument, 0, (int) OPT_SQL_BIN_UPDATE_SAME}, {"sql-mode", required_argument, 0, (int) OPT_SQL_MODE}, #include "sslopt-longopts.h" @@ -2738,6 +2801,12 @@ CHANGEABLE_VAR changeable_vars[] = { DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1 }, { "flush_time", (long*) &flush_time, FLUSH_TIME, 0, ~0L, 0, 1 }, + { "ft_min_word_len", (long*) &ft_min_word_len, + 4, 1, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len", (long*) &ft_max_word_len, + HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len_for_sort",(long*) &ft_max_word_len_for_sort, + 20, 4, HA_FT_MAXLEN, 0, 1 }, #ifdef HAVE_GEMINI_DB { "gemini_buffer_cache", (long*) &gemini_buffer_cache, 128 * 8192, 16, LONG_MAX, 0, 1 }, @@ -2811,13 +2880,15 @@ CHANGEABLE_VAR changeable_vars[] = { 0, 1, ~0L, 0, 1 }, { "max_write_lock_count", (long*) &max_write_lock_count, ~0L, 1, ~0L, 0, 1 }, - { "myisam_sort_buffer_size", (long*) &myisam_sort_buffer_size, + { "myisam_bulk_insert_tree_size", (long*) &myisam_bulk_insert_tree_size, 8192*1024, 4, ~0L, 0, 1 }, { "myisam_max_extra_sort_file_size", (long*) &myisam_max_extra_sort_file_size, (long) (MI_MAX_TEMP_LENGTH/(1024L*1024L)), 0, ~0L, 0, 1 }, { "myisam_max_sort_file_size", (long*) &myisam_max_sort_file_size, (long) (LONG_MAX/(1024L*1024L)), 0, ~0L, 0, 1 }, + { "myisam_sort_buffer_size", (long*) &myisam_sort_buffer_size, + 8192*1024, 4, ~0L, 0, 1 }, { "net_buffer_length", (long*) &net_buffer_length, 16384, 1024, 1024*1024L, MALLOC_OVERHEAD, 1024 }, { "net_retry_count", (long*) &mysqld_net_retry_count, @@ -2881,6 +2952,9 @@ struct show_var_st init_vars[]= { {"delayed_queue_size", (char*) &delayed_queue_size, SHOW_LONG}, {"flush", (char*) &myisam_flush, SHOW_MY_BOOL}, {"flush_time", (char*) &flush_time, SHOW_LONG}, + {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, + {"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG}, + {"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG}, #ifdef HAVE_GEMINI_DB {"gemini_buffer_cache", (char*) &gemini_buffer_cache, SHOW_LONG}, {"gemini_connection_limit", (char*) &gemini_connection_limit, SHOW_LONG}, @@ -2896,7 +2970,8 @@ struct show_var_st init_vars[]= { {"have_innodb", (char*) &have_innodb, SHOW_HAVE}, {"have_isam", (char*) &have_isam, SHOW_HAVE}, {"have_raid", (char*) &have_raid, SHOW_HAVE}, - {"have_ssl", (char*) &have_ssl, SHOW_HAVE}, + {"have_symlink", (char*) &have_symlink, SHOW_HAVE}, + {"have_openssl", (char*) &have_openssl, SHOW_HAVE}, {"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR}, #ifdef HAVE_INNOBASE_DB {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR}, @@ -2935,11 +3010,12 @@ struct show_var_st init_vars[]= { {"max_user_connections", (char*) &max_user_connections, SHOW_LONG}, {"max_tmp_tables", (char*) &max_tmp_tables, SHOW_LONG}, {"max_write_lock_count", (char*) &max_write_lock_count, SHOW_LONG}, - {"myisam_recover_options", (char*) &myisam_recover_options, SHOW_LONG}, + {"myisam_bulk_insert_tree_size", (char*) &myisam_bulk_insert_tree_size, SHOW_INT}, {"myisam_max_extra_sort_file_size", (char*) &myisam_max_extra_sort_file_size, SHOW_LONG}, {"myisam_max_sort_file_size",(char*) &myisam_max_sort_file_size, SHOW_LONG}, {"myisam_sort_buffer_size", (char*) &myisam_sort_buffer_size, SHOW_LONG}, + {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, {"net_buffer_length", (char*) &net_buffer_length, SHOW_LONG}, {"net_read_timeout", (char*) &net_read_timeout, SHOW_LONG}, {"net_retry_count", (char*) &mysqld_net_retry_count, SHOW_LONG}, @@ -3027,6 +3103,23 @@ struct show_var_st status_vars[]= { {"Sort_range", (char*) &filesort_range_count, SHOW_LONG}, {"Sort_rows", (char*) &filesort_rows, SHOW_LONG}, {"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG}, +#ifdef HAVE_OPENSSL + {"SSL_CTX_sess_accept", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT}, + {"SSL_CTX_sess_accept_good", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD}, + {"SSL_CTX_sess_accept_renegotiate", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE}, + {"SSL_CTX_sess_cb_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS}, + {"SSL_CTX_sess_number", (char*) 0, SHOW_SSL_CTX_SESS_NUMBER}, + {"SSL_CTX_get_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE}, + {"SSL_CTX_sess_get_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE}, + {"SSL_CTX_get_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE}, + {"SSL_CTX_get_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH}, + {"SSL_get_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE}, + {"SSL_get_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH}, + {"SSL_session_reused", (char*) 0, SHOW_SSL_SESSION_REUSED}, + {"SSL_get_version", (char*) 0, SHOW_SSL_GET_VERSION}, + {"SSL_get_cipher", (char*) 0, SHOW_SSL_GET_CIPHER}, + {"SSL_get_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT}, +#endif /* HAVE_OPENSSL */ {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_CONST}, @@ -3119,9 +3212,6 @@ static void usage(void) puts("\ -O, --set-variable var=option\n\ Give a variable an value. --help lists variables\n\ - -Sg, --skip-grant-tables\n\ - Start without grant tables. This gives all users\n\ - FULL ACCESS to all tables!\n\ --safe-mode Skip some optimize stages (for testing)\n\ --safe-show-database Don't show databases for which the user has no\n\ privileges\n\ @@ -3131,6 +3221,8 @@ static void usage(void) Don't use concurrent insert with MyISAM\n\ --skip-delay-key-write\n\ Ignore the delay_key_write option for all tables\n\ + --skip-grant-tables Start without grant tables. This gives all users\n\ + FULL ACCESS to all tables!\n\ --skip-host-cache Don't cache host names\n\ --skip-locking Don't use system locking. To use isamchk one has\n\ to shut down the server.\n\ @@ -3141,6 +3233,7 @@ static void usage(void) /* We have to break the string here because of VC++ limits */ puts("\ --skip-stack-trace Don't print a stack trace on failure\n\ + --skip-symlink Don't allow symlinking of tables\n\ --skip-show-database Don't allow 'SHOW DATABASE' commands\n\ --skip-thread-priority\n\ Don't give threads different priorities.\n\ @@ -3276,7 +3369,7 @@ static void set_options(void) #endif #if defined( HAVE_mit_thread ) || defined( __WIN__ ) || defined( HAVE_LINUXTHREADS ) - my_disable_locking = 1; + my_disable_locking=myisam_single_user= 1; #endif my_bind_addr = htonl( INADDR_ANY ); } @@ -3288,6 +3381,9 @@ static void get_options(int argc,char **argv) int c,option_index=0; myisam_delay_key_write=1; // Allow use of this + my_use_symdir=1; // Use internal symbolic links + + optind = 0; // setup in case getopt() was called previously while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvWI?", long_options, &option_index)) != EOF) { @@ -3341,6 +3437,15 @@ static void get_options(int argc,char **argv) safemalloc_mem_limit = atoi(optarg); #endif break; + case OPT_SLAVE_LOAD_TMPDIR: + slave_load_tmpdir = my_strdup(optarg, MYF(MY_FAE)); + break; + case OPT_OLD_RPL_COMPAT: + opt_old_rpl_compat = 1; + break; + case OPT_SHOW_SLAVE_AUTH_INFO: + opt_show_slave_auth_info = 1; + break; case OPT_SOCKET: mysql_unix_port= optarg; break; @@ -3373,20 +3478,6 @@ static void get_options(int argc,char **argv) test_flags= optarg ? (uint) atoi(optarg) : 0; opt_endinfo=1; break; - case 'S': - if (!optarg) - opt_specialflag|= SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE; - else if (!strcmp(optarg,"l")) - my_disable_locking=1; - else if (!strcmp(optarg,"g")) - opt_noacl=1; - else - { - fprintf(stderr,"%s: Unrecognized option: %s\n",my_progname,optarg); - use_help(); - exit(1); - } - break; case (int) OPT_BIG_TABLES: thd_startup_options|=OPTION_BIG_TABLES; break; @@ -3558,6 +3649,8 @@ static void get_options(int argc,char **argv) myisam_concurrent_insert=0; myisam_recover_options= HA_RECOVER_NONE; my_disable_symlinks=1; + my_use_symdir=0; + have_symlink=SHOW_OPTION_DISABLED; ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED; break; case (int) OPT_SAFE: @@ -3576,7 +3669,7 @@ static void get_options(int argc,char **argv) opt_noacl=1; break; case (int) OPT_SKIP_LOCK: - my_disable_locking=1; + my_disable_locking=myisam_single_user= 1; break; case (int) OPT_SKIP_HOST_CACHE: opt_specialflag|= SPECIAL_NO_HOST_CACHE; @@ -3593,6 +3686,9 @@ static void get_options(int argc,char **argv) case (int) OPT_LONG_FORMAT: opt_specialflag|=SPECIAL_LONG_LOG_FORMAT; break; + case (int) OPT_NO_MIX_TYPE: + opt_no_mix_types = 1; + break; case (int) OPT_SKIP_NETWORKING: opt_disable_networking=1; mysql_port=0; @@ -3614,8 +3710,10 @@ static void get_options(int argc,char **argv) case (int) OPT_SKIP_STACK_TRACE: test_flags|=TEST_NO_STACKTRACE; break; - case (int) OPT_SKIP_SYMLINKS: + case (int) OPT_SKIP_SYMLINK: my_disable_symlinks=1; + my_use_symdir=0; + have_symlink=SHOW_OPTION_DISABLED; break; case (int) OPT_BIND_ADDRESS: if (optarg && isdigit(optarg[0])) @@ -3803,13 +3901,16 @@ static void get_options(int argc,char **argv) case OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT: innobase_flush_log_at_trx_commit= optarg ? test(atoi(optarg)) : 1; break; - case OPT_INNODB_UNIX_FILE_FLUSH_METHOD: + case OPT_INNODB_FLUSH_METHOD: innobase_unix_file_flush_method=optarg; break; #endif /* HAVE_INNOBASE_DB */ + case OPT_DO_PSTACK: + opt_do_pstack = 1; + break; case OPT_MYISAM_RECOVER: { - if (!optarg) + if (!optarg || !optarg[0]) { myisam_recover_options= HA_RECOVER_DEFAULT; myisam_recover_options_str= myisam_recover_typelib.type_names[0]; @@ -3856,6 +3957,29 @@ static void get_options(int argc,char **argv) case OPT_MASTER_PORT: master_port= atoi(optarg); break; +#ifdef HAVE_OPENSSL + case OPT_MASTER_SSL: + master_ssl=atoi(optarg); + break; + case OPT_MASTER_SSL_KEY: + master_ssl_key=optarg; + break; + case OPT_MASTER_SSL_CERT: + master_ssl_cert=optarg; + break; +#endif /* HAVE_OPENSSL */ + case OPT_REPORT_HOST: + report_host=optarg; + break; + case OPT_REPORT_USER: + report_user=optarg; + break; + case OPT_REPORT_PASSWORD: + report_password=optarg; + break; + case OPT_REPORT_PORT: + report_port= atoi(optarg); + break; case OPT_MASTER_CONNECT_RETRY: master_connect_retry= atoi(optarg); break; @@ -3885,6 +4009,7 @@ static void get_options(int argc,char **argv) use_help(); exit(1); } + optind = 0; // setup so that getopt_long() can be called again fix_paths(); default_table_type_name=ha_table_typelib.type_names[default_table_type-1]; default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation]; @@ -4419,6 +4544,14 @@ static void fix_paths(void) mysql_tmpdir=(char*) my_realloc(mysql_tmpdir,(uint) strlen(mysql_tmpdir)+1, MYF(MY_HOLD_ON_ERROR)); } + if (!slave_load_tmpdir) + { + int copy_len; + slave_load_tmpdir = (char*) my_malloc((copy_len=strlen(mysql_tmpdir) + 1) + , MYF(MY_FAE)); + // no need to check return value, if we fail, my_malloc() never returns + memcpy(slave_load_tmpdir, mysql_tmpdir, copy_len); + } } @@ -4493,6 +4626,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib) DBUG_PRINT("enter",("x: '%s'",x)); found=0; + found_end= 0; pos=(my_string) x; while (*pos == ' ') pos++; found_end= *pos == 0; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 4d4603ed586..fded2c3ce32 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library 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 Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -22,10 +22,16 @@ ** 3 byte length & 1 byte package-number. */ +#ifdef EMBEDDED_LIBRARY +#define net_read_timeout net_read_timeout1 +#define net_write_timeout net_write_timeout1 +#endif + #ifdef __WIN__ #include <winsock.h> #endif #include <global.h> +#include <mysql_com.h> #include <violite.h> #include <my_sys.h> #include <m_string.h> @@ -34,14 +40,23 @@ #include <signal.h> #include <errno.h> #include <sys/types.h> -#include <violite.h> +#include <assert.h> + +extern "C" { #ifdef MYSQL_SERVER ulong max_allowed_packet=65536; extern ulong net_read_timeout,net_write_timeout; extern uint test_flags; #else -ulong max_allowed_packet=16*1024*1024L; + +/* +** Give error if a too big packet is found +** The server can change this with the -O switch, but because the client +** can't normally do this the client should have a bigger max_allowed_packet. +*/ + +ulong max_allowed_packet=~0L; ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; #endif @@ -90,28 +105,25 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a #endif #ifdef MYSQL_SERVER -extern ulong bytes_sent, bytes_received; +extern ulong bytes_sent, bytes_received; extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #else #undef statistic_add #define statistic_add(A,B,C) #endif -/* -** Give error if a too big packet is found -** The server can change this with the -O switch, but because the client -** can't normally do this the client should have a bigger max-buffer. -*/ - #define TEST_BLOCKING 8 -static int net_write_buff(NET *net,const char *packet,uint len); +static int net_write_buff(NET *net,const char *packet,ulong len); +#define MAX_THREE_BYTES 255L*255L*255L /* Init with packet info */ int my_net_init(NET *net, Vio* vio) { - if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME)))) + if (!(net->buff=(uchar*) my_malloc(net_buffer_length+ + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) return 1; if (net_buffer_length > max_allowed_packet) max_allowed_packet=net_buffer_length; @@ -158,8 +170,12 @@ static my_bool net_realloc(NET *net, ulong length) net->last_errno=ER_NET_PACKET_TOO_LARGE; return 1; } - pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); - if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME)))) + pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); + /* We must allocate some extra bytes for the end 0 and to be able to + read big compressed blocks */ + if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length + + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) { net->error=1; #ifdef MYSQL_SERVER @@ -215,18 +231,34 @@ int net_flush(NET *net) ** Write something to server/client buffer *****************************************************************************/ - /* ** Write a logical packet with packet header ** Format: Packet length (3 bytes), packet number(1 byte) ** When compression is used a 3 byte compression length is added -** NOTE: If compression is used the original package is destroyed! +** NOTE: If compression is used the original package is modified! */ int my_net_write(NET *net,const char *packet,ulong len) { uchar buff[NET_HEADER_SIZE]; + /* + Big packets are handled by splitting them in packets of MAX_THREE_BYTES + length. The last packet is always a packet that is < MAX_THREE_BYTES. + (The last packet may even have a lengt of 0) + */ + while (len >= MAX_THREE_BYTES) + { + const ulong z_size = MAX_THREE_BYTES; + int3store(buff, z_size); + buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) || + net_write_buff(net, packet, z_size)) + return 1; + packet += z_size; + len-= z_size; + } + /* Write last packet */ int3store(buff,len); buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE)) @@ -234,23 +266,54 @@ my_net_write(NET *net,const char *packet,ulong len) return net_write_buff(net,packet,len); } +/* + Send a command to the server. + As the command is part of the first data packet, we have to do some data + juggling to put the command in there, without having to create a new + packet. + This function will split big packets into sub-packets if needed. + (Each sub packet can only be 2^24 bytes) +*/ + int net_write_command(NET *net,uchar command,const char *packet,ulong len) { - uchar buff[NET_HEADER_SIZE+1]; uint length=len+1; /* 1 extra byte for command */ + uchar buff[NET_HEADER_SIZE+1]; + uint header_size=NET_HEADER_SIZE+1; + buff[4]=command; /* For first packet */ + if (length >= MAX_THREE_BYTES) + { + /* Take into account that we have the command in the first header */ + len= MAX_THREE_BYTES -1; + do + { + int3store(buff, MAX_THREE_BYTES); + buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + if (net_write_buff(net,(char*) buff, header_size) || + net_write_buff(net,packet,len)) + return 1; + packet+= len; + length-= MAX_THREE_BYTES; + len=MAX_THREE_BYTES; + header_size=NET_HEADER_SIZE; + } while (length >= MAX_THREE_BYTES); + len=length; /* Data left to be written */ + } int3store(buff,length); buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); - buff[4]=command; - if (net_write_buff(net,(char*) buff,5)) - return 1; - return test(net_write_buff(net,packet,len) || net_flush(net)); + return test(net_write_buff(net,(char*) buff,header_size) || + net_write_buff(net,packet,len) || net_flush(net)); } +/* + Caching the data in a local buffer before sending it. + One can force the buffer to be flushed with 'net_flush'. +*/ static int -net_write_buff(NET *net,const char *packet,uint len) +net_write_buff(NET *net,const char *packet,ulong len) { uint left_length=(uint) (net->buff_end - net->write_pos); @@ -269,7 +332,11 @@ net_write_buff(NET *net,const char *packet,uint len) return 0; } -/* Read and write using timeouts */ + +/* + Read and write one packet using timeouts. + If needed, the packet is compressed before sending. +*/ int net_real_write(NET *net,const char *packet,ulong len) @@ -432,20 +499,26 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed) if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L) { my_bool interrupted = vio_should_retry(net->vio); - if (!thr_got_alarm(alarmed) && interrupted) - { /* Probably in MIT threads */ + if (!thr_got_alarm(&alarmed) && interrupted) + { /* Probably in MIT threads */ if (retry_count++ < RETRY_COUNT) continue; } return; } - remain -=(ulong) length; - statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received); + remain -= length; + statistic_add(bytes_received,length,&LOCK_bytes_received); } } #endif /* MYSQL_SERVER */ +/* + Reads one packet to net->buff + net->where_b + Returns length of packet. Long packets are handled by my_net_read(). + This function reallocates the net->buff buffer if necessary. +*/ + static uint my_real_read(NET *net, ulong *complen) { @@ -582,12 +655,13 @@ my_real_read(NET *net, ulong *complen) #endif len=uint3korr(net->buff+net->where_b); + if (!len) /* End of big multi-packet */ + goto end; helping = max(len,*complen) + net->where_b; /* The necessary size of net->buff */ if (helping >= net->max_packet) { - /* We must allocate one extra byte for the end null */ - if (net_realloc(net,helping+1)) + if (net_realloc(net,helping)) { #ifdef MYSQL_SERVER if (i == 1) @@ -612,7 +686,21 @@ end: return(len); } -uint + +/* + Read a packet from the client/server and return it without the internal + package header. + If the packet is the first packet of a multi-packet packet + (which is indicated by the length of the packet = 0xffffff) then + all sub packets are read and concatenated. + If the packet was compressed, its uncompressed and the length of the + uncompressed packet is returned. + + The function returns the length of the found packet or packet_error. + net->read_pos points to the read data. +*/ + +ulong my_net_read(NET *net) { ulong len,complen; @@ -621,65 +709,128 @@ my_net_read(NET *net) if (!net->compress) { #endif - len = my_real_read (net,&complen); + len = my_real_read(net,&complen); + if (len == MAX_THREE_BYTES) + { + /* First packet of a multi-packet. Concatenate the packets */ + int save_pos = net->where_b; + ulong total_length=0; + do + { + net->where_b += len; + total_length += len; + len = my_real_read (net,&complen); + } while (len == MAX_THREE_BYTES); + if (len != packet_error) + len+= total_length; + net->where_b = save_pos; + } net->read_pos = net->buff + net->where_b; if (len != packet_error) net->read_pos[len]=0; /* Safeguard for mysql_use_result */ return len; #ifdef HAVE_COMPRESS } - if (net->remain_in_buf) - net->buff[net->buf_length - net->remain_in_buf]=net->save_char; - for (;;) + else { + /* We are using the compressed protocol */ + + ulong buf_length= net->buf_length; + ulong start_of_packet= net->buf_length - net->remain_in_buf; + ulong first_packet_offset=start_of_packet; + uint read_length, multi_byte_packet=0; + if (net->remain_in_buf) { - uchar *pos = net->buff + net->buf_length - net->remain_in_buf; - if (net->remain_in_buf >= 4) + /* Restore the character that was overwritten by the end 0 */ + net->buff[start_of_packet]=net->save_char; + } + else + { + /* reuse buffer, as there is noting in it that we need */ + buf_length=start_of_packet=first_packet_offset=0; + } + for (;;) + { + ulong packet_len; + + if (buf_length - start_of_packet >= NET_HEADER_SIZE) { - net->length = uint3korr(pos); - if (net->length <= net->remain_in_buf - 4) + read_length = uint3korr(net->buff+start_of_packet); + if (!read_length) + { + /* End of multi-byte packet */ + start_of_packet += NET_HEADER_SIZE; + break; + } + if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet) { - /* We have a full packet */ - len=net->length; - net->remain_in_buf -= net->length + 4; - net->read_pos=pos + 4; - break; /* We have a full packet */ + if (multi_byte_packet) + { + /* Remove packet header for second packet */ + memmove(net->buff + first_packet_offset + start_of_packet, + net->buff + first_packet_offset + start_of_packet + + NET_HEADER_SIZE, + buf_length - start_of_packet); + start_of_packet += read_length; + buf_length -= NET_HEADER_SIZE; + } + else + start_of_packet+= read_length + NET_HEADER_SIZE; + + if (read_length != MAX_THREE_BYTES) /* last package */ + { + multi_byte_packet= 0; // No last zero length packet + break; + } + multi_byte_packet= NET_HEADER_SIZE; + /* Move data down to read next data packet after current one */ + if (first_packet_offset) + { + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; + } + continue; } } /* Move data down to read next data packet after current one */ - if (net->buf_length != net->remain_in_buf) + if (first_packet_offset) { - memmove(net->buff,pos,net->remain_in_buf); - net->buf_length=net->remain_in_buf; + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; } - net->where_b=net->buf_length; - } - else - { - net->where_b=0; - net->buf_length=0; - } - if ((len = my_real_read(net,&complen)) == packet_error) - break; - if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen)) - { - len= packet_error; - net->error=2; /* caller will close socket */ + net->where_b=buf_length; + if ((packet_len = my_real_read(net,&complen)) == packet_error) + return packet_error; + if (my_uncompress((byte*) net->buff + net->where_b, &packet_len, + &complen)) + { + net->error=2; /* caller will close socket */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_UNCOMPRESS_ERROR; + net->last_errno=ER_NET_UNCOMPRESS_ERROR; #endif - break; + return packet_error; + } + buf_length+=packet_len; } - net->buf_length+=len; - net->remain_in_buf+=len; - } - if (len != packet_error) - { + + net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE; + net->buf_length= buf_length; + net->remain_in_buf= buf_length - start_of_packet; + len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE - + multi_byte_packet); net->save_char= net->read_pos[len]; /* Must be saved */ net->read_pos[len]=0; /* Safeguard for mysql_use_result */ } +#endif /* HAVE_COMPRESS */ return len; -#endif +} + } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b95b97d670f..c1911e002a3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -33,6 +33,7 @@ #include <m_ctype.h> #include <nisam.h> #include "sql_select.h" +#include <assert.h> #ifndef EXTRA_DEBUG @@ -289,7 +290,6 @@ typedef struct st_qsel_param { max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; } PARAM; - static SEL_TREE * get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value, Item_result cmp_type); @@ -382,7 +382,7 @@ SQL_SELECT::~SQL_SELECT() #undef index // Fix for Unixware 7 QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc) - :error(0),index(key_nr),max_used_key_length(0),head(table), + :dont_free(0),error(0),index(key_nr),max_used_key_length(0),head(table), it(ranges),range(0) { if (!no_alloc) @@ -399,8 +399,11 @@ QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc) QUICK_SELECT::~QUICK_SELECT() { - file->index_end(); - free_root(&alloc,MYF(0)); + if (!dont_free) + { + file->index_end(); + free_root(&alloc,MYF(0)); + } } int QUICK_SELECT::init() @@ -2455,8 +2458,8 @@ int QUICK_SELECT::get_next() if ((error=file->index_first(record))) DBUG_RETURN(error); // Empty table if (cmp_next(range) == 0) - DBUG_RETURN(0); // No matching records - range=0; // To next range + DBUG_RETURN(0); + range=0; // No matching records; go to next range continue; } if ((result = file->index_read(record,(byte*) range->min_key, @@ -2516,6 +2519,222 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range) return (range->flag & NEAR_MAX) ? 1 : 0; // Exact match } + +/* + * This is a hack: we inherit from QUICK_SELECT so that we can use the + * get_next() interface, but we have to hold a pointer to the original + * QUICK_SELECT because its data are used all over the place. What + * should be done is to factor out the data that is needed into a base + * class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC) + * which handle the ranges and implement the get_next() function. But + * for now, this seems to work right at least. + */ + +QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts) + : QUICK_SELECT(*q), rev_it(rev_ranges) +{ + bool not_read_after_key = file->option_flag() & HA_NOT_READ_AFTER_KEY; + for (QUICK_RANGE *r = it++; r; r = it++) + { + rev_ranges.push_front(r); + if (not_read_after_key && range_reads_after_key(r) || + test_if_null_range(r,used_key_parts)) + { + it.rewind(); // Reset range + error = HA_ERR_UNSUPPORTED; + dont_free=1; // Don't free memory from 'q' + return; + } + } + /* Remove EQ_RANGE flag for keys that are not using the full key */ + for (QUICK_RANGE *r = rev_it++; r; r = rev_it++) + { + if ((r->flag & EQ_RANGE) && + head->key_info[index].key_length != r->max_length) + r->flag&= ~EQ_RANGE; + } + rev_it.rewind(); + q->dont_free=1; // Don't free shared mem + delete q; +} + + +int QUICK_SELECT_DESC::get_next() +{ + DBUG_ENTER("QUICK_SELECT_DESC::get_next"); + + /* The max key is handled as follows: + * - if there is NO_MAX_RANGE, start at the end and move backwards + * - if it is an EQ_RANGE, which means that max key covers the entire + * key, go directly to the key and read through it (sorting backwards is + * same as sorting forwards) + * - if it is NEAR_MAX, go to the key or next, step back once, and + * move backwards + * - otherwise (not NEAR_MAX == include the key), go after the key, + * step back once, and move backwards + */ + + for (;;) + { + int result; + if (range) + { // Already read through key + result = ((range->flag & EQ_RANGE) + ? file->index_next_same(record, (byte*) range->min_key, + range->min_length) : + file->index_prev(record)); + if (!result) + { + if (cmp_prev(*rev_it.ref()) == 0) + DBUG_RETURN(0); + } + else if (result != HA_ERR_END_OF_FILE) + DBUG_RETURN(result); + } + + if (!(range=rev_it++)) + DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used + + if (range->flag & NO_MAX_RANGE) // Read last record + { + int error; + if ((error=file->index_last(record))) + DBUG_RETURN(error); // Empty table + if (cmp_prev(range) == 0) + DBUG_RETURN(0); + range=0; // No matching records; go to next range + continue; + } + + if (range->flag & EQ_RANGE) + { + result = file->index_read(record, (byte*) range->max_key, + range->max_length, HA_READ_KEY_EXACT); + } + else + { + dbug_assert(range->flag & NEAR_MAX || range_reads_after_key(range)); + /* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will + * do the right thing - go past all keys which match the prefix */ + result=file->index_read(record, (byte*) range->max_key, + range->max_length, + ((range->flag & NEAR_MAX) ? + HA_READ_KEY_EXACT : HA_READ_AFTER_KEY)); + result = file->index_prev(record); + } + if (result) + { + if (result != HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(result); + range=0; // Not found, to next range + continue; + } + if (cmp_prev(range) == 0) + { + if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) + range = 0; // Stop searching + DBUG_RETURN(0); // Found key is in range + } + range = 0; // To next range + } +} + +/* + * Returns 0 if found key is inside range (found key >= range->min_key). + */ +int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range) +{ + if (range->flag & NO_MIN_RANGE) + return (0); /* key can't be to small */ + + KEY_PART *key_part = key_parts; + for (char *key = range->min_key, *end = key + range->min_length; + key < end; + key += key_part++->part_length) + { + int cmp; + if (key_part->null_bit) + { + // this key part allows null values; NULL is lower than everything else + if (*key++) + { + // the range is expecting a null value + if (!key_part->field->is_null()) + return 0; // not null -- still inside the range + continue; // null -- exact match, go to next key part + } + else if (key_part->field->is_null()) + return 1; // null -- outside the range + } + if ((cmp = key_part->field->key_cmp((byte*) key, + key_part->part_length)) > 0) + return 0; + if (cmp < 0) + return 1; + } + return (range->flag & NEAR_MIN) ? 1 : 0; // Exact match +} + +/* + * True if this range will require using HA_READ_AFTER_KEY + See comment in get_next() about this + */ + +bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range) +{ + return ((range->flag & (NO_MAX_RANGE | NEAR_MAX)) || + !(range->flag & EQ_RANGE) || + head->key_info[index].key_length != range->max_length) ? 1 : 0; +} + +/* True if we are reading over a key that may have a NULL value */ + +bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range, + uint used_key_parts) +{ + uint offset,end; + KEY_PART *key_part = key_parts, + *key_part_end= key_part+used_key_parts; + + for (offset= 0, end = min(range->min_length, range->max_length) ; + offset < end && key_part != key_part_end ; + offset += key_part++->part_length) + { + uint null_length=test(key_part->null_bit); + if (!memcmp((char*) range->min_key+offset, (char*) range->max_key+offset, + key_part->part_length + null_length)) + { + offset+=null_length; + continue; + } + if (null_length && range->min_key[offset]) + return 1; // min_key is null and max_key isn't + // Range doesn't cover NULL. This is ok if there is no more null parts + break; + } + /* + If the next min_range is > NULL, then we can use this, even if + it's a NULL key + Example: SELECT * FROM t1 WHERE a = 2 AND b >0 ORDER BY a DESC,b DESC; + + */ + if (key_part != key_part_end && key_part->null_bit) + { + if (offset >= range->min_length || range->min_key[offset]) + return 1; // Could be null + key_part++; + } + /* + If any of the key parts used in the ORDER BY could be NULL, we can't + use the key to sort the data. + */ + for (; key_part != key_part_end ; key_part++) + if (key_part->null_bit) + return 1; // Covers null part + return 0; +} + + /***************************************************************************** ** Print a quick range for debugging ** TODO: diff --git a/sql/opt_range.h b/sql/opt_range.h index 247dd260817..50215b94be0 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -54,9 +54,10 @@ class QUICK_RANGE :public Sql_alloc { {} }; + class QUICK_SELECT { public: - bool next; + bool next,dont_free; int error; uint index,max_used_key_length; TABLE *head; @@ -80,6 +81,21 @@ public: bool unique_key_range(); }; + +class QUICK_SELECT_DESC: public QUICK_SELECT +{ +public: + QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts); + int get_next(); +private: + int cmp_prev(QUICK_RANGE *range); + bool range_reads_after_key(QUICK_RANGE *range); + bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); + void reset(void) { next=0; rev_it.rewind(); } + List<QUICK_RANGE> rev_ranges; + List_iterator<QUICK_RANGE> rev_it; +}; + class SQL_SELECT :public Sql_alloc { public: QUICK_SELECT *quick; // If quick-select used diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index df49d52d54a..c16c0d919d4 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -32,7 +32,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond); int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) { - List_iterator<Item> it(all_fields); + List_iterator_fast<Item> it(all_fields); int const_result=1; bool recalc_const_item=0; table_map removed_tables=0; @@ -205,7 +205,7 @@ uint count_table_entries(COND *cond,TABLE *table) if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC) return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); Item *item; uint count=0; while ((item=li++)) @@ -250,7 +250,7 @@ bool part_of_cond(COND *cond,Field *field) if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC) return 0; // Already checked - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); Item *item; while ((item=li++)) { diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 6bc05aa33cd..cb3056b5f5a 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -27,5 +27,11 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/charsets/Index $(DESTDIR)$(pkgdatadir)/charsets/Index $(INSTALL_DATA) $(srcdir)/charsets/*.conf $(DESTDIR)$(pkgdatadir)/charsets +fix_errors: + for lang in @AVAILABLE_LANGUAGES@; \ + do \ + ../../extra/comp_err $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \ + done + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index index b91e27e7c02..5cf30682cc0 100644 --- a/sql/share/charsets/Index +++ b/sql/share/charsets/Index @@ -1,6 +1,7 @@ # sql/share/charsets/Index # -# This file lists all of the available character sets. +# This file lists all of the available character sets. Please keep this +# file sorted by character set number. big5 1 @@ -34,3 +35,4 @@ croat 27 gbk 28 cp1257 29 latin5 30 +latin1_de 31 diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 1ca2aa9b02b..6097679b3d3 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -14,198 +14,198 @@ "isamchk", "NE", "ANO", -"Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)",-A -"Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)",-A -"Nemohu vytvo-Bøit databázi '%-.64s', chyba %d",-A -"Nemohu vytvo-Bøit databázi '%-.64s', databáze ji¾ existuje",-A -"Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje",-A -"Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)",-A -"Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)",-A -"Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)",-A -"Nemohu -Bèíst záznam v systémové tabulce",-A -"Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)",-A -"Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)",-A -"Nemohu uzamknout soubor (chybov-Bý kód: %d)",-A -"Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)",-A -"Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)",-A -"Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)",-A -"Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)",-A -"Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'",-A -"Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ...",-A -"Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'",-A -"Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)",-A -"Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)",-A -"Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)",-A -"Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)",-A -"'%-.64s' je zam-Bèen proti zmìnám",-A -"T-Bøídìní pøeru¹eno",-A +"Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)", +"Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)", +"Nemohu vytvo-Bøit databázi '%-.64s', chyba %d", +"Nemohu vytvo-Bøit databázi '%-.64s', databáze ji¾ existuje", +"Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje", +"Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)", +"Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)", +"Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)", +"Nemohu -Bèíst záznam v systémové tabulce", +"Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)", +"Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)", +"Nemohu uzamknout soubor (chybov-Bý kód: %d)", +"Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)", +"Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)", +"Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)", +"Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)", +"Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'", +"Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ...", +"Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'", +"Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)", +"Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)", +"Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)", +"Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)", +"'%-.64s' je zam-Bèen proti zmìnám", +"T-Bøídìní pøeru¹eno", "Pohled '%-.64s' pro '%-.64s' neexistuje", -"Obsluha tabulky vr-Bátila chybu %d",-A -"Obsluha tabulky '%-.64s' nem-Bá tento parametr",-A -"Nemohu naj-Bít záznam v '%-.64s'",-A -"Nespr-Bávná informace v souboru '%-.64s'",-A -"Nespr-Bávný klíè pro tabulku '%-.64s'. Pokuste se ho opravit",-A -"Star-Bý klíèový soubor pro '%-.64s'. Opravte ho.",-A -"'%-.64s' je jen pro -Bètení",-A -"M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)",-A -"M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu",-A -"Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)",-A -"P-Bøíli¹ mnoho spojení",-A -"M-Bálo prostoru/pamìti pro thread",-A -"Nemohu zjistit jm-Béno stroje pro Va¹i adresu",-A -"Chyba p-Bøi ustavování spojení",-A -"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' k databázi '%-.64s' není povolen",-A -"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' (s heslem %s)",-A -"Nebyla vybr-Bána ¾ádná databáze",-A -"Nezn-Bámý pøíkaz",-A -"Sloupec '%-.64s' nem-Bù¾e být null",-A -"Nezn-Bámá databáze '%-.64s'",-A -"Tabulka '%-.64s' ji-B¾ existuje",-A -"Nezn-Bámá tabulka '%-.64s'",-A -"Sloupec '%-.64s' v %s nen-Bí zcela jasný",-A -"Prob-Bíhá ukonèování práce serveru",-A -"Nezn-Bámý sloupec '%-.64s' v %s",-A -"Pou-B¾ité '%-.64s' nebylo v group by",-A -"Nemohu pou-B¾ít group na '%-.64s'",-A -"P-Bøíkaz obsahuje zároveò funkci sum a sloupce",-A -"Po-Bèet sloupcù neodpovídá zadané hodnotì",-A -"Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé",-A -"Zdvojen-Bé jméno sloupce '%-.64s'",-A -"Zdvojen-Bé jméno klíèe '%-.64s'",-A -"Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)",-A -"Chybn-Bá specifikace sloupce '%-.64s'",-A -"%s bl-Bízko '%-.64s' na øádku %d",-A -"V-Býsledek dotazu je prázdný",-A -"Nejednozna-Bèná tabulka/alias: '%-.64s'",-A -"Chybn-Bá defaultní hodnota pro '%-.64s'",-A -"Definov-Báno více primárních klíèù",-A -"Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù",-A -"Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí",-A -"Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d",-A -"Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje",-A -"Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè",-A -"P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB",-A -"M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè",-A -"%s: p-Bøipraven na spojení\n",-A -"%s: norm-Bální ukonèení\n",-A -"%s: p-Bøijat signal %d, konèím\n",-A -"%s: ukon-Bèení práce hotovo\n",-A -"%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n",-A -"Nemohu vytvo-Bøit IP socket",-A -"Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu",-A -"Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál",-A -"Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'.",-A -"Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny",-A -"Soubor '%-.64s' ji-B¾ existuje",-A -"Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld",-A -"Z-Báznamù: %ld Zdvojených: %ld",-A -"Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe",-A -"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",-A -"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",-A -"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld",-A -"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM",-A -"Nezn-Bámá identifikace threadu: %lu",-A -"Nejste vlastn-Bíkem threadu %lu",-A -"Nejsou pou-B¾ity ¾ádné tabulky",-A -"P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET",-A -"Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n",-A -"Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna",-A -"Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES",-A -"Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu",-A -"Nep-Bøípustné jméno databáze '%-.64s'",-A -"Nep-Bøípustné jméno tabulky '%-.64s'",-A -"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET OPTION SQL_BIG_SELECTS=1",-A -"Nezn-Bámá chyba",-A -"Nezn-Bámá procedura %s",-A -"Chybn-Bý poèet parametrù procedury %s",-A -"Chybn-Bé parametry procedury %s",-A -"Nezn-Bámá tabulka '%-.64s' v %s",-A -"Polo-B¾ka '%-.64s' je zadána dvakrát",-A -"Nespr-Bávné pou¾ití funkce group",-A -"Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není",-A -"Tabulka mus-Bí mít alespoò jeden sloupec",-A -"Tabulka '%-.64s' je pln-Bá",-A -"Nezn-Bámá znaková sada: '%-.64s'",-A -"P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d",-A -"P-Bøíli¹ mnoho polo¾ek",-A -"-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %d. Musíte zmìnit nìkteré polo¾ky na blob",-A -"P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku",-A -"V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky",-A -"Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL",-A -"Nemohu na-Bèíst funkci '%-.64s'",-A +"Obsluha tabulky vr-Bátila chybu %d", +"Obsluha tabulky '%-.64s' nem-Bá tento parametr", +"Nemohu naj-Bít záznam v '%-.64s'", +"Nespr-Bávná informace v souboru '%-.64s'", +"Nespr-Bávný klíè pro tabulku '%-.64s'. Pokuste se ho opravit", +"Star-Bý klíèový soubor pro '%-.64s'. Opravte ho.", +"'%-.64s' je jen pro -Bètení", +"M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)", +"M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu", +"Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)", +"P-Bøíli¹ mnoho spojení", +"M-Bálo prostoru/pamìti pro thread", +"Nemohu zjistit jm-Béno stroje pro Va¹i adresu", +"Chyba p-Bøi ustavování spojení", +"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' k databázi '%-.64s' není povolen", +"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' (s heslem %s)", +"Nebyla vybr-Bána ¾ádná databáze", +"Nezn-Bámý pøíkaz", +"Sloupec '%-.64s' nem-Bù¾e být null", +"Nezn-Bámá databáze '%-.64s'", +"Tabulka '%-.64s' ji-B¾ existuje", +"Nezn-Bámá tabulka '%-.64s'", +"Sloupec '%-.64s' v %s nen-Bí zcela jasný", +"Prob-Bíhá ukonèování práce serveru", +"Nezn-Bámý sloupec '%-.64s' v %s", +"Pou-B¾ité '%-.64s' nebylo v group by", +"Nemohu pou-B¾ít group na '%-.64s'", +"P-Bøíkaz obsahuje zároveò funkci sum a sloupce", +"Po-Bèet sloupcù neodpovídá zadané hodnotì", +"Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé", +"Zdvojen-Bé jméno sloupce '%-.64s'", +"Zdvojen-Bé jméno klíèe '%-.64s'", +"Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)", +"Chybn-Bá specifikace sloupce '%-.64s'", +"%s bl-Bízko '%-.64s' na øádku %d", +"V-Býsledek dotazu je prázdný", +"Nejednozna-Bèná tabulka/alias: '%-.64s'", +"Chybn-Bá defaultní hodnota pro '%-.64s'", +"Definov-Báno více primárních klíèù", +"Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù", +"Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí", +"Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d", +"Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje", +"Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè", +"P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB", +"M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè", +"%s: p-Bøipraven na spojení\n", +"%s: norm-Bální ukonèení\n", +"%s: p-Bøijat signal %d, konèím\n", +"%s: ukon-Bèení práce hotovo\n", +"%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n", +"Nemohu vytvo-Bøit IP socket", +"Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu", +"Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál", +"Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'.", +"Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny", +"Soubor '%-.64s' ji-B¾ existuje", +"Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld", +"Z-Báznamù: %ld Zdvojených: %ld", +"Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe", +"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE", +"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe", +"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld", +"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM", +"Nezn-Bámá identifikace threadu: %lu", +"Nejste vlastn-Bíkem threadu %lu", +"Nejsou pou-B¾ity ¾ádné tabulky", +"P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET", +"Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n", +"Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna", +"Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES", +"Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu", +"Nep-Bøípustné jméno databáze '%-.64s'", +"Nep-Bøípustné jméno tabulky '%-.64s'", +"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET OPTION SQL_BIG_SELECTS=1", +"Nezn-Bámá chyba", +"Nezn-Bámá procedura %s", +"Chybn-Bý poèet parametrù procedury %s", +"Chybn-Bé parametry procedury %s", +"Nezn-Bámá tabulka '%-.64s' v %s", +"Polo-B¾ka '%-.64s' je zadána dvakrát", +"Nespr-Bávné pou¾ití funkce group", +"Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není", +"Tabulka mus-Bí mít alespoò jeden sloupec", +"Tabulka '%-.64s' je pln-Bá", +"Nezn-Bámá znaková sada: '%-.64s'", +"P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d", +"P-Bøíli¹ mnoho polo¾ek", +"-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %d. Musíte zmìnit nìkteré polo¾ky na blob", +"P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku", +"V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky", +"Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL", +"Nemohu na-Bèíst funkci '%-.64s'", "Nemohu inicializovat funkci '%-.64s'; %-.80s", -"Pro sd-Bílenou knihovnu nejsou povoleny cesty",-A -"Funkce '%-.64s' ji-B¾ existuje",-A -"Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %s)",-A -"Nemohu naj-Bít funkci '%-.64s' v knihovnì'",-A -"Funkce '%-.64s' nen-Bí definována",-A -"Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'",-A -"Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit",-A -"Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla",-A -"Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql",-A -"V tabulce user nen-Bí ¾ádný odpovídající øádek",-A -"Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld",-A -"Nemohu vytvo-Bøit nový thread (errno %d). Pokud je je¹tì nìjaká volná pamì», podívejte se do manuálu na èást o chybách specifických pro jednotlivé operaèní systémy",-A -"Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld",-A -"Nemohu znovuotev-Bøít tabulku: '%-.64s',-A -"Neplatn-Bé u¾ití hodnoty NULL",-A -"Regul-Bární výraz vrátil chybu '%-.64s'",-A -"Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami",-A -"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'",-A -"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro tabulku '%-.64s'",-A -"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",-A -"Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.",-A -"Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý",-A +"Pro sd-Bílenou knihovnu nejsou povoleny cesty", +"Funkce '%-.64s' ji-B¾ existuje", +"Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %s)", +"Nemohu naj-Bít funkci '%-.64s' v knihovnì'", +"Funkce '%-.64s' nen-Bí definována", +"Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'", +"Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit", +"Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla", +"Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql", +"V tabulce user nen-Bí ¾ádný odpovídající øádek", +"Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld", +"Nemohu vytvo-Bøit nový thread (errno %d). Pokud je je¹tì nìjaká volná pamì», podívejte se do manuálu na èást o chybách specifických pro jednotlivé operaèní systémy", +"Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld", +"Nemohu znovuotev-Bøít tabulku: '%-.64s', +"Neplatn-Bé u¾ití hodnoty NULL", +"Regul-Bární výraz vrátil chybu '%-.64s'", +"Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami", +"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'", +"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro tabulku '%-.64s'", +"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'", +"Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.", +"Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý", "Tabulka '%-64s.%s' neexistuje", -"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'",-A -"Pou-B¾itý pøíkaz není v této verzi MySQL povolen",-A -"Va-B¹e syntaxe je nìjaká divná",-A -"Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s",-A -"P-Bøíli¹ mnoho zpo¾dìných threadù",-A -"Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)",-A -"Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'",-A -"Zji-B¹tìna chyba pøi ètení z roury spojení",-A -"Zji-B¹tìna chyba fcntl()",-A -"P-Bøíchozí packety v chybném poøadí",-A -"Nemohu rozkomprimovat komunika-Bèní packet",-A -"Zji-B¹tìna chyba pøi ètení komunikaèního packetu",-A -"Zji-B¹tìn timeout pøi ètení komunikaèního packetu",-A -"Zji-B¹tìna chyba pøi zápisu komunikaèního packetu",-A -"Zji-B¹tìn timeout pøi zápisu komunikaèního packetu",-A -"V-Býsledný øetìzec je del¹í ne¾ max_allowed_packet",-A -"Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce",-A -"Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce",-A -"INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES",-A -"Nespr-Bávné jméno sloupce '%-.100s'",-A -"Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'",-A -"V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì",-A -"Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'",-A -"BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky",-A -"V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE",-A -"V-Býsledek obsahuje více ne¾ jeden øádek",-A -"Tento typ tabulky vy-B¾aduje primární klíè",-A -"Tato verze MySQL nen-Bí zkompilována s podporou RAID",-A -"Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno",-A -"Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje",-A -"Nemohu otev-Bøít tabulku",-A +"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'", +"Pou-B¾itý pøíkaz není v této verzi MySQL povolen", +"Va-B¹e syntaxe je nìjaká divná", +"Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s", +"P-Bøíli¹ mnoho zpo¾dìných threadù", +"Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)", +"Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'", +"Zji-B¹tìna chyba pøi ètení z roury spojení", +"Zji-B¹tìna chyba fcntl()", +"P-Bøíchozí packety v chybném poøadí", +"Nemohu rozkomprimovat komunika-Bèní packet", +"Zji-B¹tìna chyba pøi ètení komunikaèního packetu", +"Zji-B¹tìn timeout pøi ètení komunikaèního packetu", +"Zji-B¹tìna chyba pøi zápisu komunikaèního packetu", +"Zji-B¹tìn timeout pøi zápisu komunikaèního packetu", +"V-Býsledný øetìzec je del¹í ne¾ max_allowed_packet", +"Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce", +"Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce", +"INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES", +"Nespr-Bávné jméno sloupce '%-.100s'", +"Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'", +"V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì", +"Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'", +"BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky", +"V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE", +"V-Býsledek obsahuje více ne¾ jeden øádek", +"Tento typ tabulky vy-B¾aduje primární klíè", +"Tato verze MySQL nen-Bí zkompilována s podporou RAID", +"Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno", +"Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje", +"Nemohu otev-Bøít tabulku", "Handler tabulky nepodporuje check/repair", -"Proveden-Bí tohoto pøíkazu není v transakci dovoleno",-A -"Chyba %d p-Bøi COMMIT",-A -"Chyba %d p-Bøi ROLLBACK",-A -"Chyba %d p-Bøi FLUSH_LOGS",-A -"Chyba %d p-Bøi CHECKPOINT",-A -"Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno",-A -"Handler tabulky nepodporuje bin-Bární dump",-A -"Binlog uzav-Bøen pøi pokusu o FLUSH MASTER",-A -"P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né",-A +"Proveden-Bí tohoto pøíkazu není v transakci dovoleno", +"Chyba %d p-Bøi COMMIT", +"Chyba %d p-Bøi ROLLBACK", +"Chyba %d p-Bøi FLUSH_LOGS", +"Chyba %d p-Bøi CHECKPOINT", +"Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno", +"Handler tabulky nepodporuje bin-Bární dump", +"Binlog uzav-Bøen pøi pokusu o FLUSH MASTER", +"P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né", "Chyba masteru: '%-.64s'", -"S-Bí»ová chyba pøi ètení z masteru",-A -"S-Bí»ová chyba pøi zápisu na master",-A -"-B®ádný sloupec nemá vytvoøen fulltextový index",-A -"Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce",-A -"Nezn-Bámá systémová promìnná '%-.64'",-A -"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena",-A -"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila",-A +"S-Bí»ová chyba pøi ètení z masteru", +"S-Bí»ová chyba pøi zápisu na master", +"-B®ádný sloupec nemá vytvoøen fulltextový index", +"Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce", +"Nezn-Bámá systémová promìnná '%-.64'", +"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena", +"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila", "Warning: Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", @@ -223,3 +223,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index e6c828625eb..805740664d0 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -217,3 +217,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index abaa475402e..245ff40cf86 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -218,3 +218,10 @@ "Foutieve parameters voor %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 7fc0928d67d..185d8ffbe33 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -214,3 +214,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index d9c98fa919d..5023ead91e7 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -218,3 +218,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 6dc6f150d57..1f282dc078d 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -214,3 +214,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 262390d42ea..dd744ecab46 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -217,3 +217,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 146f196852b..850bac1756b 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -214,3 +214,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 1d76fd1d898..6e1d1af015e 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -216,3 +216,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 79e8c8aed8b..5d10578a6cf 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -214,3 +214,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 2971882d431..1ed9b4aa346 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -216,3 +216,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 7fbc60b8953..8b2d689bff5 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -214,3 +214,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 9fb3f5f5666..267eae13d67 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -216,3 +216,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index cc04859d99d..8a7112ac0c1 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -216,3 +216,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 989c1f7f45d..6ae12f7bff1 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -218,3 +218,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 82670f503b0..787fae883ea 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -214,3 +214,10 @@ "Argumentos errados para %s", "Não é permitido a %-.32s@%-.64s criar novos usuários", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index ba214e540e6..a09a8046b29 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -218,3 +218,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 94889100847..e4de072bf67 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -217,3 +217,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 652f50c77c8..9b4491a3258 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -222,3 +222,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error connecting to master: %-.128s", +"Error running query on master: %-.128s", +"Error when executing command %s: %-.128s", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 271b362f63f..165fcb1d538 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -215,3 +215,10 @@ "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", "Incorrect table definition; All MERGE tables must be in the same database", +"Error de coneccion a master: %-128s", +"Error executando el query en master: %-128%", +"Error de %s: %-128%", +"Wrong usage of %s and %s", +"The used SELECT statements have a different number of columns", +"Can't execute the query because you have a conflicting read lock", +"Mixing of transactional and non-transactional tables is disabled", diff --git a/sql/share/swedish/errmsg.OLD b/sql/share/swedish/errmsg.OLD index cc54e051e63..3dd14c8b613 100644 --- a/sql/share/swedish/errmsg.OLD +++ b/sql/share/swedish/errmsg.OLD @@ -205,11 +205,17 @@ "Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'", "Kunde inte starta en tråd för replikering", "Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar", -"Du kan endast använda konstant-uttryck med SET", -"Lock wait timeout exceeded", -"The total number of locks exceeds the lock table size", -"Update locks cannot be acquired during a READ UNCOMMITTED transaction", -"DROP DATABASE not allowed while thread is holding global read lock", -"CREATE DATABASE not allowed while thread is holding global read lock", -#ER_WRONG_ARGUMENTS +"Man kan endast använda konstant-uttryck med SET", +"Fick inte ett lås i tid", +"Antal lås överskrider antalet reserverade lås", +"Updaterings-lås kan inte göras när man använder READ UNCOMMITTED", +"DROP DATABASE är inte tillåtet när man har ett globalt läs-lås", +"CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås", "Felaktiga argument till %s", +"%-.32s@%-.64s har inte rättigheter att skapa nya användare", +"Fick fel vid anslutning till master: %-.128s", +"Fick fel vid utförande av command på mastern: %-.128s", +"Fick fel vid utförande av %s: %-.128s", +"Felaktig använding av %s and %s", +"SELECT kommandona har olika antal kolumner" +"Kan inte utföra kommandot emedan du har ett READ lås", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 1eb3e9db1e7..095a05faf34 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -212,5 +212,12 @@ "DROP DATABASE är inte tillåtet när man har ett globalt läs-lås", "CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås", "Felaktiga argument till %s", -"%-.32s@%-.64s har inte rättigheter att skapa nya användare", +"%-.32s@%-.64s har inte rättighet att skapa nya användare", "Felaktig tabell definition: Alla tabeller i en MERGE tabell måste vara i samma databas", +"Fick fel vid anslutning till master: %-.128s", +"Fick fel vid utförande av command på mastern: %-.128s", +"Fick fel vid utförande av %s: %-.128s", +"Felaktig använding av %s and %s", +"SELECT kommandona har olika antal kolumner" +"Kan inte utföra kommandot emedan du har ett READ lås", +"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat", diff --git a/sql/slave.cc b/sql/slave.cc index f6e8822ea14..6b79e639a90 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -20,13 +20,12 @@ #include <myisam.h> #include "mini_client.h" #include "slave.h" +#include "sql_repl.h" #include <thr_alarm.h> #include <my_dir.h> -#define RPL_LOG_NAME (glob_mi.log_file_name[0] ? glob_mi.log_file_name :\ - "FIRST") - volatile bool slave_running = 0; +char* slave_load_tmpdir = 0; pthread_t slave_real_id; MASTER_INFO glob_mi; HASH replicate_do_table, replicate_ignore_table; @@ -40,26 +39,26 @@ THD* slave_thd = 0; // when slave thread exits, we need to remember the temporary tables so we // can re-use them on slave start -static int last_slave_errno = 0; -static char last_slave_error[1024] = ""; +int last_slave_errno = 0; +char last_slave_error[MAX_SLAVE_ERRMSG] = ""; #ifndef DBUG_OFF int disconnect_slave_event_count = 0, abort_slave_event_count = 0; -static int events_till_disconnect = -1, events_till_abort = -1; +static int events_till_disconnect = -1; +int events_till_abort = -1; static int stuck_count = 0; #endif -inline void skip_load_data_infile(NET* net); +void skip_load_data_infile(NET* net); inline bool slave_killed(THD* thd); static int init_slave_thread(THD* thd); static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi); static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi); static int safe_sleep(THD* thd, int sec); -static int request_table_dump(MYSQL* mysql, char* db, char* table); +static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int create_table_from_dump(THD* thd, NET* net, const char* db, const char* table_name); -inline char* rewrite_db(char* db); -static int check_expected_error(THD* thd, int expected_error); +char* rewrite_db(char* db); static void free_table_ent(TABLE_RULE_ENT* e) { @@ -218,7 +217,16 @@ inline bool slave_killed(THD* thd) return abort_slave || abort_loop || thd->killed; } -inline void skip_load_data_infile(NET* net) +void slave_print_error(int err_code, const char* msg, ...) +{ + va_list args; + va_start(args,msg); + my_vsnprintf(last_slave_error, sizeof(last_slave_error), msg, args); + sql_print_error("Slave: %s, error_code=%d", last_slave_error, err_code); + last_slave_errno = err_code; +} + +void skip_load_data_infile(NET* net) { (void)my_net_write(net, "\xfb/dev/null", 10); (void)net_flush(net); @@ -226,7 +234,7 @@ inline void skip_load_data_infile(NET* net) send_ok(net); // the master expects it } -inline char* rewrite_db(char* db) +char* rewrite_db(char* db) { if(replicate_rewrite_db.is_empty() || !db) return db; I_List_iterator<i_string_pair> it(replicate_rewrite_db); @@ -360,7 +368,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Creating table from master dump"; // save old db in case we are creating in a different database char* save_db = thd->db; - thd->db = thd->last_nx_db; + thd->db = (char*)db; mysql_parse(thd, thd->query, packet_len); // run create table thd->db = save_db; // leave things the way the were before @@ -409,32 +417,42 @@ err: return error; } -int fetch_nx_table(THD* thd, MASTER_INFO* mi) +int fetch_nx_table(THD* thd, const char* db_name, const char* table_name, + MASTER_INFO* mi, MYSQL* mysql) { - MYSQL* mysql = mc_mysql_init(NULL); int error = 1; int nx_errno = 0; - if (!mysql) - { + bool called_connected = (mysql != NULL); + if (!called_connected && !(mysql = mc_mysql_init(NULL))) + { sql_print_error("fetch_nx_table: Error in mysql_init()"); nx_errno = ER_GET_ERRNO; goto err; } - safe_connect(thd, mysql, mi); + if (!called_connected) + { + if (connect_to_master(thd, mysql, mi)) + { + sql_print_error("Could not connect to master while fetching table\ + '%-64s.%-64s'", db_name, table_name); + nx_errno = ER_CONNECT_TO_MASTER; + goto err; + } + } if (slave_killed(thd)) goto err; - if (request_table_dump(mysql, thd->last_nx_db, thd->last_nx_table)) + if (request_table_dump(mysql, db_name, table_name)) { nx_errno = ER_GET_ERRNO; sql_print_error("fetch_nx_table: failed on table dump request "); goto err; } - if (create_table_from_dump(thd, &mysql->net, thd->last_nx_db, - thd->last_nx_table)) - { + if (create_table_from_dump(thd, &mysql->net, db_name, + table_name)) + { // create_table_from_dump will have sent the error alread sql_print_error("fetch_nx_table: failed on create table "); goto err; @@ -443,7 +461,7 @@ int fetch_nx_table(THD* thd, MASTER_INFO* mi) error = 0; err: - if (mysql) + if (mysql && !called_connected) mc_mysql_close(mysql); if (nx_errno && thd->net.vio) send_error(&thd->net, nx_errno, "Error in fetch_nx_table"); @@ -470,7 +488,7 @@ int init_master_info(MASTER_INFO* mi) MY_STAT stat_area; char fname[FN_REFLEN+128]; const char *msg; - fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32); + fn_format(fname, master_info_file, mysql_data_home, "", 4+32); // we need a mutex while we are changing master info parameters to // keep other threads from reading bogus info @@ -547,7 +565,9 @@ int init_master_info(MASTER_INFO* mi) master_password) || init_intvar_from_file((int*)&mi->port, &mi->file, master_port) || init_intvar_from_file((int*)&mi->connect_retry, &mi->file, - master_connect_retry)) + master_connect_retry) || + init_intvar_from_file((int*)&mi->last_log_seq, &mi->file, 0) + ) { msg="Error reading master configuration"; goto error; @@ -570,6 +590,44 @@ error: return 1; } +int register_slave_on_master(MYSQL* mysql) +{ + String packet; + uint len; + char buf[4]; + + if(!report_host) + return 0; + + int4store(buf, server_id); + packet.append(buf, 4); + + net_store_data(&packet, report_host); + if(report_user) + net_store_data(&packet, report_user); + else + packet.append((char)0); + + if(report_password) + net_store_data(&packet, report_user); + else + packet.append((char)0); + + int2store(buf, (uint16)report_port); + packet.append(buf, 2); + + if(mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), + packet.length(), 0)) + { + sql_print_error("Error on COM_REGISTER_SLAVE: '%s'", + mc_mysql_error(mysql)); + return 1; + } + + return 0; +} + + int show_master_info(THD* thd) { DBUG_ENTER("show_master_info"); @@ -589,10 +647,12 @@ int show_master_info(THD* thd) field_list.push_back(new Item_empty_string("Last_errno", 4)); field_list.push_back(new Item_empty_string("Last_error", 20)); field_list.push_back(new Item_empty_string("Skip_counter", 12)); + field_list.push_back(new Item_empty_string("Last_log_seq", 12)); if(send_fields(thd, field_list, 1)) DBUG_RETURN(-1); String* packet = &thd->packet; + uint32 last_log_seq; packet->length(0); pthread_mutex_lock(&glob_mi.lock); @@ -601,16 +661,18 @@ int show_master_info(THD* thd) net_store_data(packet, (uint32) glob_mi.port); net_store_data(packet, (uint32) glob_mi.connect_retry); net_store_data(packet, glob_mi.log_file_name); - net_store_data(packet, (uint32) glob_mi.pos); // QQ: Should be fixed + net_store_data(packet, (longlong) glob_mi.pos); + last_log_seq = glob_mi.last_log_seq; pthread_mutex_unlock(&glob_mi.lock); - pthread_mutex_lock(&LOCK_slave); + pthread_mutex_lock(&LOCK_slave); // QQ; This is not needed net_store_data(packet, slave_running ? "Yes":"No"); - pthread_mutex_unlock(&LOCK_slave); + pthread_mutex_unlock(&LOCK_slave); // QQ; This is not needed net_store_data(packet, &replicate_do_db); net_store_data(packet, &replicate_ignore_db); net_store_data(packet, (uint32)last_slave_errno); net_store_data(packet, last_slave_error); net_store_data(packet, slave_skip_counter); + net_store_data(packet, last_log_seq); if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); @@ -623,11 +685,13 @@ int flush_master_info(MASTER_INFO* mi) { IO_CACHE* file = &mi->file; char lbuf[22]; + char lbuf1[22]; my_b_seek(file, 0L); - my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", + my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n", mi->log_file_name, llstr(mi->pos, lbuf), mi->host, mi->user, - mi->password, mi->port, mi->connect_retry); + mi->password, mi->port, mi->connect_retry, + llstr(mi->last_log_seq, lbuf1)); flush_io_cache(file); return 0; } @@ -775,7 +839,7 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi) return 0; } -static int request_table_dump(MYSQL* mysql, char* db, char* table) +static int request_table_dump(MYSQL* mysql, const char* db, const char* table) { char buf[1024]; char * p = buf; @@ -847,7 +911,7 @@ server_errno=%d)", return len - 1; } -static int check_expected_error(THD* thd, int expected_error) +int check_expected_error(THD* thd, int expected_error) { switch(expected_error) { @@ -878,12 +942,13 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) if (ev) { int type_code = ev->get_type_code(); + int exec_res; if (ev->server_id == ::server_id || slave_skip_counter) { if(type_code == LOAD_EVENT) skip_load_data_infile(net); - mi->inc_pos(event_len); + mi->inc_pos(event_len, ev->log_seq); flush_master_info(mi); if(slave_skip_counter) --slave_skip_counter; @@ -893,270 +958,14 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query - if(!ev->when) + if(!thd->log_seq) + thd->log_seq = ev->log_seq; + if (!ev->when) ev->when = time(NULL); - - switch(type_code) { - case QUERY_EVENT: - { - Query_log_event* qev = (Query_log_event*)ev; - int q_len = qev->q_len; - int expected_error,actual_error = 0; - init_sql_alloc(&thd->mem_root, 8192,0); - thd->db = rewrite_db((char*)qev->db); - if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) - { - thd->query = (char*)qev->query; - thd->set_time((time_t)qev->when); - thd->current_tablenr = 0; - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id = query_id++; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->last_nx_table = thd->last_nx_db = 0; - thd->query_error = 0; // clear error - thd->net.last_errno = 0; - thd->net.last_error[0] = 0; - thd->slave_proxy_id = qev->thread_id; // for temp tables - - // sanity check to make sure the master did not get a really bad - // error on the query - if (!check_expected_error(thd, (expected_error = qev->error_code))) - { - mysql_parse(thd, thd->query, q_len); - if (expected_error != - (actual_error = thd->net.last_errno) && expected_error) - { - const char* errmsg = "Slave: did not get the expected error\ - running query from master - expected: '%s'(%d), got '%s'(%d)"; - sql_print_error(errmsg, ER_SAFE(expected_error), - expected_error, - actual_error ? thd->net.last_error:"no error", - actual_error); - thd->query_error = 1; - } - else if (expected_error == actual_error) - { - thd->query_error = 0; - *last_slave_error = 0; - last_slave_errno = 0; - } - } - else - { - // master could be inconsistent, abort and tell DBA to check/fix it - thd->db = thd->query = 0; - thd->convert_set = 0; - close_thread_tables(thd); - free_root(&thd->mem_root,0); - delete ev; - return 1; - } - } - thd->db = 0; // prevent db from being freed - thd->query = 0; // just to be sure - // assume no convert for next query unless set explictly - thd->convert_set = 0; - close_thread_tables(thd); - - if (thd->query_error || thd->fatal_error) - { - sql_print_error("Slave: error running query '%s' ", - qev->query); - last_slave_errno = actual_error ? actual_error : -1; - my_snprintf(last_slave_error, sizeof(last_slave_error), - "error '%s' on query '%s'", - actual_error ? thd->net.last_error : - "unexpected success or fatal error", - qev->query - ); - free_root(&thd->mem_root,0); - delete ev; - return 1; - } - free_root(&thd->mem_root,0); - delete ev; - - mi->inc_pos(event_len); - flush_master_info(mi); - break; - } - - case LOAD_EVENT: - { - Load_log_event* lev = (Load_log_event*)ev; - init_sql_alloc(&thd->mem_root, 8192,0); - thd->db = rewrite_db((char*)lev->db); - thd->query = 0; - thd->query_error = 0; - - if(db_ok(thd->db, replicate_do_db, replicate_ignore_db)) - { - thd->set_time((time_t)lev->when); - thd->current_tablenr = 0; - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id = query_id++; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - - TABLE_LIST tables; - bzero((char*) &tables,sizeof(tables)); - tables.db = thd->db; - tables.name = tables.real_name = (char*)lev->table_name; - tables.lock_type = TL_WRITE; - // the table will be opened in mysql_load - if(table_rules_on && !tables_ok(thd, &tables)) - { - skip_load_data_infile(net); - } - else - { - enum enum_duplicates handle_dup = DUP_IGNORE; - if(lev->sql_ex.opt_flags && REPLACE_FLAG) - handle_dup = DUP_REPLACE; - sql_exchange ex((char*)lev->fname, lev->sql_ex.opt_flags && - DUMPFILE_FLAG ); - String field_term(&lev->sql_ex.field_term, 1), - enclosed(&lev->sql_ex.enclosed, 1), - line_term(&lev->sql_ex.line_term,1), - escaped(&lev->sql_ex.escaped, 1), - line_start(&lev->sql_ex.line_start, 1); - - ex.field_term = &field_term; - if(lev->sql_ex.empty_flags & FIELD_TERM_EMPTY) - ex.field_term->length(0); - - ex.enclosed = &enclosed; - if(lev->sql_ex.empty_flags & ENCLOSED_EMPTY) - ex.enclosed->length(0); - - ex.line_term = &line_term; - if(lev->sql_ex.empty_flags & LINE_TERM_EMPTY) - ex.line_term->length(0); - - ex.line_start = &line_start; - if(lev->sql_ex.empty_flags & LINE_START_EMPTY) - ex.line_start->length(0); - - ex.escaped = &escaped; - if(lev->sql_ex.empty_flags & ESCAPED_EMPTY) - ex.escaped->length(0); - - ex.opt_enclosed = (lev->sql_ex.opt_flags & OPT_ENCLOSED_FLAG); - if(lev->sql_ex.empty_flags & FIELD_TERM_EMPTY) - ex.field_term->length(0); - - ex.skip_lines = lev->skip_lines; - - - List<Item> fields; - lev->set_fields(fields); - thd->slave_proxy_id = thd->thread_id; - thd->net.vio = net->vio; - // mysql_load will use thd->net to read the file - thd->net.pkt_nr = net->pkt_nr; - // make sure the client does not get confused - // about the packet sequence - if(mysql_load(thd, &ex, &tables, fields, handle_dup, 1, - TL_WRITE)) - thd->query_error = 1; - if(thd->cuted_fields) - sql_print_error("Slave: load data infile at position %s in log \ -'%s' produced %d warning(s)", llstr(glob_mi.pos,llbuff), RPL_LOG_NAME, - thd->cuted_fields ); - net->pkt_nr = thd->net.pkt_nr; - } - } - else - { - // we will just ask the master to send us /dev/null if we do not - // want to load the data :-) - skip_load_data_infile(net); - } - - thd->net.vio = 0; - thd->db = 0;// prevent db from being freed - close_thread_tables(thd); - if(thd->query_error) - { - int sql_error = thd->net.last_errno; - if(!sql_error) - sql_error = ER_UNKNOWN_ERROR; - - sql_print_error("Slave: Error '%s' running load data infile ", - ER(sql_error)); - delete ev; - free_root(&thd->mem_root,0); - return 1; - } - - delete ev; - free_root(&thd->mem_root,0); - - if(thd->fatal_error) - { - sql_print_error("Slave: Fatal error running query '%s' ", - thd->query); - return 1; - } - - mi->inc_pos(event_len); - flush_master_info(mi); - break; - } - - case START_EVENT: - close_temporary_tables(thd); - mi->inc_pos(event_len); - flush_master_info(mi); - delete ev; - break; - - case STOP_EVENT: - if(mi->pos > 4) // stop event should be ignored after rotate event - { - close_temporary_tables(thd); - mi->inc_pos(event_len); - flush_master_info(mi); - } - delete ev; - break; - case ROTATE_EVENT: - { - Rotate_log_event* rev = (Rotate_log_event*)ev; - int ident_len = rev->ident_len; - pthread_mutex_lock(&mi->lock); - memcpy(mi->log_file_name, rev->new_log_ident,ident_len ); - mi->log_file_name[ident_len] = 0; - mi->pos = 4; // skip magic number - pthread_cond_broadcast(&mi->cond); - pthread_mutex_unlock(&mi->lock); - flush_master_info(mi); -#ifndef DBUG_OFF - if(abort_slave_event_count) - ++events_till_abort; -#endif - delete ev; - break; - } - - case INTVAR_EVENT: - { - Intvar_log_event* iev = (Intvar_log_event*)ev; - switch(iev->type) - { - case LAST_INSERT_ID_EVENT: - thd->last_insert_id_used = 1; - thd->last_insert_id = iev->val; - break; - case INSERT_ID_EVENT: - thd->next_insert_id = iev->val; - break; - - } - mi->inc_pending(event_len); - delete ev; - break; - } - } + ev->thd = thd; + exec_res = ev->exec_event(mi); + delete ev; + return exec_res; } else { @@ -1166,7 +975,6 @@ This may also be a network problem, or just a bug in the master or slave code.\ "); return 1; } - return 0; } // slave thread @@ -1251,8 +1059,15 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) sql_print_error("Slave thread killed while connecting to master"); goto err; } - + connected: + + thd->slave_net = &mysql->net; + // register ourselves with the master + // if fails, this is not fatal - we just print the error message and go + // on with life + thd->proc_info = "Registering slave on master"; + register_slave_on_master(mysql); while (!slave_killed(thd)) { @@ -1299,6 +1114,7 @@ try again, log '%s' at postion %s", RPL_LOG_NAME, goto connected; } + while(!slave_killed(thd)) { thd->proc_info = "Reading master update"; @@ -1308,6 +1124,7 @@ try again, log '%s' at postion %s", RPL_LOG_NAME, sql_print_error("Slave thread killed while reading event"); goto err; } + if (event_len == packet_error) { diff --git a/sql/slave.h b/sql/slave.h index 1932bcb04fe..5850b57d3b3 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -1,9 +1,11 @@ #ifndef SLAVE_H #define SLAVE_H +#include "mysql.h" #define SLAVE_NET_TIMEOUT 3600 extern ulong slave_net_timeout; +extern char* slave_load_tmpdir; typedef struct st_master_info { @@ -17,11 +19,12 @@ typedef struct st_master_info char password[HASH_PASSWORD_LENGTH+1]; uint port; uint connect_retry; + uint32 last_log_seq; // log sequence number of last processed event pthread_mutex_t lock; pthread_cond_t cond; bool inited; - st_master_info():pending(0),fd(-1),inited(0) + st_master_info():pending(0),fd(-1),last_log_seq(0),inited(0) { host[0] = 0; user[0] = 0; password[0] = 0; pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); @@ -37,11 +40,12 @@ typedef struct st_master_info { pending += val; } - inline void inc_pos(ulonglong val) + inline void inc_pos(ulonglong val, uint32 log_seq) { pthread_mutex_lock(&lock); pos += val + pending; pending = 0; + last_log_seq = log_seq; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&lock); } @@ -66,14 +70,23 @@ typedef struct st_table_rule_ent #define TABLE_RULE_HASH_SIZE 16 #define TABLE_RULE_ARR_SIZE 16 +#define MAX_SLAVE_ERRMSG 1024 + +#define RPL_LOG_NAME (glob_mi.log_file_name[0] ? glob_mi.log_file_name :\ + "FIRST") + int flush_master_info(MASTER_INFO* mi); +int register_slave_on_master(MYSQL* mysql); -int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd = -1); +int mysql_table_dump(THD* thd, const char* db, + const char* tbl_name, int fd = -1); // if fd is -1, dump to NET -int fetch_nx_table(THD* thd, MASTER_INFO* mi); + +int fetch_nx_table(THD* thd, const char* db_name, const char* table_name, + MASTER_INFO* mi, MYSQL* mysql); // retrieve non-exitent table from master -// the caller must set thd->last_nx_table and thd->last_nx_db first + int show_master_info(THD* thd); int show_binlog_info(THD* thd); @@ -89,6 +102,10 @@ int add_table_rule(HASH* h, const char* table_spec); int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); void init_table_rule_hash(HASH* h, bool* h_inited); void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); +char* rewrite_db(char* db); +int check_expected_error(THD* thd, int error_code); +void skip_load_data_infile(NET* net); +void slave_print_error(int err_code, const char* msg, ...); void end_slave(); // clean up int init_master_info(MASTER_INFO* mi); @@ -101,6 +118,11 @@ extern uint32 slave_skip_counter; // we want to restart it skipping one or more events in the master log that // have caused errors, and have been manually applied by DBA already +extern int last_slave_errno; +#ifndef DBUG_OFF +extern int events_till_abort; +#endif +extern char last_slave_error[MAX_SLAVE_ERRMSG]; extern pthread_t slave_real_id; extern THD* slave_thd; extern MASTER_INFO glob_mi; @@ -115,9 +137,9 @@ extern int disconnect_slave_event_count, abort_slave_event_count ; #endif // the master variables are defaults read from my.cnf or command line -extern uint master_port, master_connect_retry; +extern uint master_port, master_connect_retry, report_port; extern my_string master_user, master_password, master_host, - master_info_file; + master_info_file, report_user, report_host, report_password; extern I_List<i_string> replicate_do_db, replicate_ignore_db; extern I_List<i_string_pair> replicate_rewrite_db; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 798cd78cab1..bc2222ffa48 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -61,6 +61,9 @@ public: uint hostname_length; char *user,*password; ulong salt[2]; +#ifdef HAVE_OPENSSL + char *ssl_type, *ssl_cipher, *x509_issuer, *x509_subject; +#endif }; class ACL_DB :public ACL_ACCESS @@ -199,6 +202,15 @@ int acl_init(bool dont_read_acl_tables) update_hostname(&user.host,get_field(&mem, table,0)); user.user=get_field(&mem, table,1); user.password=get_field(&mem, table,2); +#ifdef HAVE_OPENSSL + DBUG_PRINT("info",("table->fields=%d",table->fields)); + if (table->fields >= 21) { + user.ssl_type=get_field(&mem, table,17); + user.ssl_cipher=get_field(&mem, table,18); + user.x509_issuer=get_field(&mem, table,19); + user.x509_subject=get_field(&mem, table,20); + } +#endif if (user.password && (length=(uint) strlen(user.password)) == 8 && protocol_version == PROTOCOL_VERSION) { @@ -1003,10 +1015,10 @@ static int replace_user_table(TABLE *table, const LEX_USER &combo, my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT), MYF(0),combo.user.str,combo.host.str); else - my_printf_error(ER_NO_PERMISSON_TO_CREATE_USER, - ER(ER_NO_PERMISSON_TO_CREATE_USER), + my_printf_error(ER_NO_PERMISSION_TO_CREATE_USER, + ER(ER_NO_PERMISSION_TO_CREATE_USER), MYF(0),thd->user, - thd->host ? thd->host : thd->ip ? thd->ip: ""); + thd->host_or_ip); error= -1; goto end; } @@ -1503,8 +1515,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, uint store_table_rights,store_col_rights; DBUG_ENTER("replace_table_table"); - strxmov(grantor,thd->user,"@",thd->host ? thd->host : thd->ip ? thd->ip :"", - NullS); + strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); // The following should always succeed as new users are created before // this function is called! @@ -2091,7 +2102,7 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, table ? table->real_name : "unknown"); } return 1; @@ -2154,7 +2165,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, MYF(0), command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, name, table ? table->real_name : "unknown"); } @@ -2212,7 +2223,7 @@ bool check_grant_all_columns(THD *thd,uint want_access, TABLE *table) MYF(0), command, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, field ? field->field_name : "unknown", table->real_name); return 1; @@ -2313,7 +2324,7 @@ uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field) static const char *command_array[]= {"SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP","RELOAD","SHUTDOWN", "PROCESS","FILE","GRANT","REFERENCES","INDEX","ALTER"}; -static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,9,5,5}; +static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,10,5,5}; int mysql_show_grants(THD *thd,LEX_USER *lex_user) { @@ -2321,7 +2332,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) int error = 0; ACL_USER *acl_user; ACL_DB *acl_db; char buff[1024]; - DBUG_ENTER("mysql_grant"); + DBUG_ENTER("mysql_show_grants"); LINT_INIT(acl_user); if (!initialized) @@ -2412,6 +2423,31 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(passd_buff); global.append('\''); } +#ifdef HAVE_OPENSSL +/* SSL grant stuff */ + DBUG_PRINT("info",("acl_user->ssl_type=%s",acl_user->ssl_type)); + DBUG_PRINT("info",("acl_user->ssl_cipher=%s",acl_user->ssl_cipher)); + DBUG_PRINT("info",("acl_user->x509_subject=%s",acl_user->x509_subject)); + DBUG_PRINT("info",("acl_user->x509_issuer=%s",acl_user->x509_issuer)); + if(acl_user->ssl_type) { + if(!strcmp(acl_user->ssl_type,"ssl")) + global.append(" REQUIRE SSL",12); + else if(!strcmp(acl_user->ssl_type,"x509")) + { + global.append(" REQUIRE X509 ",14); + if(acl_user->x509_issuer) { + global.append("SUBJECT \"",9); + global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); + global.append("\"",1); + } + if(acl_user->x509_subject) { + global.append("ISSUER \"",8); + global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); + global.append("\"",1); + } + } + } +#endif if (want_access & GRANT_ACL) global.append(" WITH GRANT OPTION",18); thd->packet.length(0); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index de367e8c052..161e0f9b2e7 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -38,6 +38,37 @@ #define UINT_MAX24 0xffffff #define UINT_MAX32 0xffffffff +int sortcmp2(void* cmp_arg __attribute__((unused)), + const String *a,const String *b) +{ + return sortcmp(a,b); +} + +int stringcmp2(void* cmp_arg __attribute__((unused)), + const String *a,const String *b) +{ + return stringcmp(a,b); +} + +int compare_double2(void* cmp_arg __attribute__((unused)), + const double *s, const double *t) +{ + return compare_double(s,t); +} + +int compare_longlong2(void* cmp_arg __attribute__((unused)), + const longlong *s, const longlong *t) +{ + return compare_longlong(s,t); +} + +int compare_ulonglong2(void* cmp_arg __attribute__((unused)), + const ulonglong *s, const ulonglong *t) +{ + return compare_ulonglong(s,t); +} + + Procedure * proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list) @@ -96,7 +127,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, pc->f_end = pc->f_info + field_list.elements; pc->fields = field_list; - List_iterator<Item> it(pc->fields); + List_iterator_fast<Item> it(pc->fields); f_info = pc->f_info; Item *item; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index ce5c0af6a96..2147f14e160 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -21,8 +21,6 @@ #pragma interface /* gcc class implementation */ #endif -#include <my_tree.h> - #define DEC_IN_AVG 4 typedef struct st_number_info @@ -53,8 +51,14 @@ uint check_ulonglong(const char *str, uint length); bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num); bool test_if_number(NUM_INFO *info, const char *str, uint str_len); int compare_double(const double *s, const double *t); +int compare_double2(void* cmp_arg __attribute__((unused)), + const double *s, const double *t); int compare_longlong(const longlong *s, const longlong *t); +int compare_longlong2(void* cmp_arg __attribute__((unused)), + const longlong *s, const longlong *t); int compare_ulonglong(const ulonglong *s, const ulonglong *t); +int compare_ulonglong2(void* cmp_arg __attribute__((unused)), + const ulonglong *s, const ulonglong *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list); void free_string(String*); @@ -91,6 +95,11 @@ public: int collect_string(String *element, element_count count, TREE_INFO *info); +int sortcmp2(void* cmp_arg __attribute__((unused)), + const String *a,const String *b); +int stringcmp2(void* cmp_arg __attribute__((unused)), + const String *a,const String *b); + class field_str :public field_info { String min_arg, max_arg; @@ -105,9 +114,9 @@ public: max_arg(""), sum(0), must_be_blob(0), was_zero_fill(0), was_maybe_zerofill(0), can_be_still_num(1) - { init_tree(&tree, 0, sizeof(String), a->binary ? - (qsort_cmp) stringcmp : (qsort_cmp) sortcmp, - 0, (void (*)(void*)) free_string); }; + { init_tree(&tree, 0, 0, sizeof(String), a->binary ? + (qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2, + 0, (tree_element_free) free_string, NULL); }; void add(); void get_opt_type(String*, ha_rows); @@ -145,8 +154,8 @@ class field_real: public field_info public: field_real(Item* a, analyse* b) :field_info(a,b), min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0) - { init_tree(&tree, 0, sizeof(double), - (qsort_cmp) compare_double, 0, NULL); } + { init_tree(&tree, 0, 0, sizeof(double), + (qsort_cmp2) compare_double2, 0, NULL, NULL); } void add(); void get_opt_type(String*, ha_rows); @@ -191,8 +200,8 @@ class field_longlong: public field_info public: field_longlong(Item* a, analyse* b) :field_info(a,b), min_arg(0), max_arg(0), sum(0), sum_sqr(0) - { init_tree(&tree, 0, sizeof(longlong), - (qsort_cmp) compare_longlong, 0, NULL); } + { init_tree(&tree, 0, 0, sizeof(longlong), + (qsort_cmp2) compare_longlong2, 0, NULL, NULL); } void add(); void get_opt_type(String*, ha_rows); @@ -236,8 +245,8 @@ class field_ulonglong: public field_info public: field_ulonglong(Item* a, analyse * b) :field_info(a,b), min_arg(0), max_arg(0), sum(0),sum_sqr(0) - { init_tree(&tree, 0, sizeof(ulonglong), - (qsort_cmp) compare_ulonglong, 0, NULL); } + { init_tree(&tree, 0, 0, sizeof(ulonglong), + (qsort_cmp2) compare_ulonglong2, 0, NULL, NULL); } void add(); void get_opt_type(String*, ha_rows); String *get_min_arg(String *s) { s->set(min_arg); return s; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 624377b688e..9ba5277a92c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -34,8 +34,6 @@ HASH open_cache; /* Used by mysql_test */ static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, const char *name, const char *alias, bool locked); -static bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, - const char *table_name, List_iterator<Item> *it); static void free_cache_entry(TABLE *entry); static void mysql_rm_tmp_tables(void); static key_map get_key_map_from_key_list(TABLE *table, @@ -111,75 +109,71 @@ static void check_unused(void) #define check_unused() #endif -int list_open_tables(THD *thd,List<char> *tables, const char *db, - const char *wild) +OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) { int result = 0; uint col_access=thd->col_access; + OPEN_TABLE_LIST **start_list, *open_list; TABLE_LIST table_list; + char name[NAME_LEN*2]; DBUG_ENTER("list_open_tables"); + VOID(pthread_mutex_lock(&LOCK_open)); bzero((char*) &table_list,sizeof(table_list)); + start_list= &open_list; + open_list=0; - for (uint idx=0 ; idx < open_cache.records; idx++) + for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++) { + OPEN_TABLE_LIST *table; TABLE *entry=(TABLE*) hash_element(&open_cache,idx); - if ((!entry->real_name) || strcmp(entry->table_cache_key,db)) - continue; - if (wild && wild[0] && wild_compare(entry->real_name,wild)) - continue; - if (db && !(col_access & TABLE_ACLS)) + + if ((!entry->real_name)) + continue; // Shouldn't happen + if (wild) { - table_list.db= (char*) db; - table_list.real_name= entry->real_name;/*real name*/ - table_list.grant.privilege=col_access; - if (check_grant(thd,TABLE_ACLS,&table_list,1,1)) - continue; + strxmov(name,entry->table_cache_key,".",entry->real_name,NullS); + if (wild_compare(name,wild)) + continue; } - /* need to check if he have't already listed it */ - List_iterator<char> it(*tables); - char *table_name; - int check = 0; - while (check == 0 && (table_name=it++)) + /* Check if user has SELECT privilege for any column in the table */ + table_list.db= (char*) entry->table_cache_key; + table_list.real_name= entry->real_name; + table_list.grant.privilege=0; + if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list)) + continue; + + /* need to check if we haven't already listed it */ + for (table= open_list ; table ; table=table->next) { - if (!strcmp(table_name,entry->real_name)) - check++; + if (!strcmp(table->table,entry->real_name) && + !strcmp(table->db,entry->table_cache_key)) + { + if (entry->in_use) + table->in_use++; + if (entry->locked_by_name) + table->locked++; + break; + } } - if (check) + if (table) continue; - - if (tables->push_back(thd->strdup(entry->real_name))) + if (!(*start_list = (OPEN_TABLE_LIST *) + sql_alloc(sizeof(OPEN_TABLE_LIST)+entry->key_length))) { - result = -1; + open_list=0; // Out of memory break; } + (*start_list)->table=(strmov((*start_list)->db=(char*) ((*start_list)+1), + entry->table_cache_key)+1, + entry->real_name); + (*start_list)->in_use= entry->in_use ? 1 : 0; + (*start_list)->locked= entry->locked_by_name ? 1 : 0; + start_list= &(*start_list)->next; } - VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_RETURN(result); -} - -char* -query_table_status(THD *thd,const char *db,const char *table_name) -{ - int cached = 0, in_use = 0; - char info[256]; - - for (uint idx=0 ; idx < open_cache.records; idx++) - { - TABLE *entry=(TABLE*) hash_element(&open_cache,idx); - if (strcmp(entry->table_cache_key,db) || - strcmp(entry->real_name,table_name)) - continue; - - cached++; - if (entry->in_use) - in_use++; - } - - sprintf(info, "cached=%d, in_use=%d", cached, in_use); - return thd->strdup(info); + DBUG_RETURN(open_list); } @@ -195,7 +189,7 @@ query_table_status(THD *thd,const char *db,const char *table_name) bool send_fields(THD *thd,List<Item> &list,uint flag) { - List_iterator<Item> it(list); + List_iterator_fast<Item> it(list); Item *item; char buff[80]; CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set; @@ -259,7 +253,7 @@ send_fields(THD *thd,List<Item> &list,uint flag) if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) break; /* purecov: inspected */ } - send_eof(&thd->net,(test_flags & TEST_MIT_THREAD) ? 0: 1); + send_eof(&thd->net); return 0; err: send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */ @@ -431,40 +425,9 @@ void close_thread_tables(THD *thd, bool locked) DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables)); - for (table=thd->open_tables ; table ; table=next) - { - next=table->next; - if (table->version != refresh_version || - thd->version != refresh_version || !table->db_stat) - { - VOID(hash_delete(&open_cache,(byte*) table)); - found_old_table=1; - } - else - { - if (table->flush_version != flush_version) - { - table->flush_version=flush_version; - table->file->extra(HA_EXTRA_FLUSH); - } - else - { - // Free memory and reset for next loop - table->file->extra(HA_EXTRA_RESET); - } - table->in_use=0; - if (unused_tables) - { - table->next=unused_tables; /* Link in last */ - table->prev=unused_tables->prev; - unused_tables->prev=table; - table->prev->next=table; - } - else - unused_tables=table->next=table->prev=table; - } - } - thd->open_tables=0; + while (thd->open_tables) + found_old_table|=close_thread_table(thd, &thd->open_tables); + /* Free tables to hold down open files */ while (open_cache.records > table_cache_size && unused_tables) VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */ @@ -480,6 +443,48 @@ void close_thread_tables(THD *thd, bool locked) DBUG_VOID_RETURN; } +/* move one table to free list */ + +bool close_thread_table(THD *thd, TABLE **table_ptr) +{ + DBUG_ENTER("close_thread_table"); + + bool found_old_table=0; + TABLE *table=*table_ptr; + + *table_ptr=table->next; + if (table->version != refresh_version || + thd->version != refresh_version || !table->db_stat) + { + VOID(hash_delete(&open_cache,(byte*) table)); + found_old_table=1; + } + else + { + if (table->flush_version != flush_version) + { + table->flush_version=flush_version; + table->file->extra(HA_EXTRA_FLUSH); + } + else + { + // Free memory and reset for next loop + table->file->extra(HA_EXTRA_RESET); + } + table->in_use=0; + if (unused_tables) + { + table->next=unused_tables; /* Link in last */ + table->prev=unused_tables->prev; + unused_tables->prev=table; + table->prev->next=table; + } + else + unused_tables=table->next=table->prev=table; + } + DBUG_RETURN(found_old_table); +} + /* Close and delete temporary tables */ void close_temporary(TABLE *table,bool delete_table) @@ -689,7 +694,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) if (thd->killed) DBUG_RETURN(0); TABLE* table; - if(!(table = table_list->table)) + if (!(table = table_list->table)) DBUG_RETURN(0); char* db = thd->db ? thd->db : table_list->db; @@ -836,25 +841,6 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key, key_length))) { - MEM_ROOT* glob_alloc; - LINT_INIT(glob_alloc); - - if (errno == ENOENT && - (glob_alloc = my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC))) - // Sasha: needed for replication - // remember the name of the non-existent table - // so we can try to download it from the master - { - int table_name_len = (uint) strlen(table_name); - int db_len = (uint) strlen(db); - thd->last_nx_db = alloc_root(glob_alloc,db_len + table_name_len + 2); - if(thd->last_nx_db) - { - thd->last_nx_table = thd->last_nx_db + db_len + 1; - memcpy(thd->last_nx_table, table_name, table_name_len + 1); - memcpy(thd->last_nx_db, db, db_len + 1); - } - } table->next=table->prev=table; free_cache_entry(table); VOID(pthread_mutex_unlock(&LOCK_open)); @@ -1337,7 +1323,7 @@ int open_tables(THD *thd,TABLE_LIST *start) { if (!tables->table && !(tables->table=open_table(thd, - tables->db ? tables->db : thd->db, + tables->db, tables->real_name, tables->name, &refresh))) { @@ -1394,7 +1380,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) DBUG_ENTER("open_ltable"); thd->proc_info="Opening table"; - while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db, + while (!(table=open_table(thd,table_list->db, table_list->real_name,table_list->name, &refresh)) && refresh) ; if (table) @@ -1626,9 +1612,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables) for (; tables ; tables=tables->next) { if (!strcmp(tables->name,table_name) && - (!db || - (tables->db && !strcmp(db,tables->db)) || - (!tables->db && !strcmp(db,thd->db)))) + (!db || !strcmp(db,tables->db))) { found_table=1; Field *find=find_field_in_table(thd,tables->table,name,length, @@ -1752,14 +1736,15 @@ find_item_in_list(Item *find,List<Item> &items) ****************************************************************************/ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, - bool set_query_id, List<Item> *sum_func_list) + bool set_query_id, List<Item> *sum_func_list, + bool allow_sum_func) { reg2 Item *item; List_iterator<Item> it(fields); DBUG_ENTER("setup_fields"); thd->set_query_id=set_query_id; - thd->allow_sum_func= test(sum_func_list); + thd->allow_sum_func= allow_sum_func; thd->where="field list"; while ((item=it++)) @@ -1775,7 +1760,8 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, { if (item->fix_fields(thd,tables)) DBUG_RETURN(-1); /* purecov: inspected */ - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && + sum_func_list) item->split_sum_func(*sum_func_list); thd->used_tables|=item->used_tables(); } @@ -1830,7 +1816,7 @@ static key_map get_key_map_from_key_list(TABLE *table, List<String> *index_list) { key_map map=0; - List_iterator<String> it(*index_list); + List_iterator_fast<String> it(*index_list); String *name; uint pos; while ((name=it++)) @@ -1851,7 +1837,7 @@ static key_map get_key_map_from_key_list(TABLE *table, ** Returns pointer to last inserted field if ok ****************************************************************************/ -static bool +bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it) { @@ -1866,8 +1852,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, check_grant_all_columns(thd,SELECT_ACL,table) ) DBUG_RETURN(-1); if (!table_name || (!strcmp(table_name,tables->name) && - (!db_name || !tables->db || - !strcmp(tables->db,db_name)))) + (!db_name || !strcmp(tables->db,db_name)))) { Field **ptr=table->field,*field; thd->used_tables|=table->map; @@ -2010,7 +1995,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) int fill_record(List<Item> &fields,List<Item> &values) { - List_iterator<Item> f(fields),v(values); + List_iterator_fast<Item> f(fields),v(values); Item *value; Item_field *field; DBUG_ENTER("fill_record"); @@ -2028,7 +2013,7 @@ fill_record(List<Item> &fields,List<Item> &values) int fill_record(Field **ptr,List<Item> &values) { - List_iterator<Item> v(values); + List_iterator_fast<Item> v(values); Item *value; DBUG_ENTER("fill_record"); @@ -2091,7 +2076,8 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) create_info.db_type=DB_TYPE_DEFAULT; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, - fields, keys, drop, alter, (ORDER*)0, FALSE, DUP_ERROR)); + fields, keys, drop, alter, (ORDER*)0, FALSE, + DUP_ERROR)); } @@ -2106,7 +2092,8 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) create_info.db_type=DB_TYPE_DEFAULT; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, - fields, keys, drop, alter, (ORDER*)0, FALSE, DUP_ERROR)); + fields, keys, drop, alter, (ORDER*)0, FALSE, + DUP_ERROR)); } /***************************************************************************** diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ace7c291ed3..b77166d0bc0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -49,6 +49,8 @@ template class List<Alter_drop>; template class List_iterator<Alter_drop>; template class List<Alter_column>; template class List_iterator<Alter_column>; +template class List<Set_option>; +template class List_iterator<Set_option>; #endif /**************************************************************************** @@ -80,12 +82,14 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), global_read_lock(0),bootstrap(0) { host=user=priv_user=db=query=ip=0; + host_or_ip="unknown ip"; locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password= query_start_used=0; query_length=col_access=0; query_error=0; next_insert_id=last_insert_id=0; - open_tables=temporary_tables=0; + open_tables=temporary_tables=handler_tables=0; + handler_items=0; tmp_table=0; lock=locked_tables=0; used_tables=0; @@ -95,7 +99,8 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), current_linfo = 0; slave_thread = 0; slave_proxy_id = 0; - last_nx_table = last_nx_db = 0; + log_seq = 0; + file_id = 0; cond_count=0; convert_set=0; mysys_var=0; @@ -117,6 +122,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), proc_info="login"; where="field list"; server_id = ::server_id; + slave_net = 0; server_status=SERVER_STATUS_AUTOCOMMIT; update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE; options=thd_startup_options; @@ -160,6 +166,11 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } + if (handler_tables) + { + open_tables=handler_tables; handler_tables=0; + close_thread_tables(this); + } close_temporary_tables(this); #ifdef USING_TRANSACTIONS if (opt_using_transactions) @@ -184,12 +195,7 @@ THD::~THD() if (!cleanup_done) cleanup(); if (global_read_lock) - { - pthread_mutex_lock(&LOCK_open); - ::global_read_lock--; - pthread_cond_broadcast(&COND_refresh); - pthread_mutex_unlock(&LOCK_open); - } + unlock_global_read_lock(this); if (ull) { pthread_mutex_lock(&LOCK_user_locks); @@ -277,7 +283,7 @@ bool select_send::send_fields(List<Item> &list,uint flag) bool select_send::send_data(List<Item> &items) { - List_iterator<Item> li(items); + List_iterator_fast<Item> li(items); String *packet= &thd->packet; DBUG_ENTER("send_data"); @@ -302,12 +308,6 @@ bool select_send::send_data(List<Item> &items) DBUG_RETURN(error); } - -void select_send::send_error(uint errcode,const char *err) -{ - ::send_error(&thd->net,errcode,err); -} - bool select_send::send_eof() { /* Unlock tables before sending packet to gain some speed */ @@ -370,7 +370,7 @@ select_export::prepare(List<Item> &list) } /* Check if there is any blobs in data */ { - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item=li++)) { @@ -417,7 +417,7 @@ bool select_export::send_data(List<Item> &items) Item *item; char *buff_ptr=buff; uint used_length=0,items_left=items.elements; - List_iterator<Item> li(items); + List_iterator_fast<Item> li(items); if (my_b_write(&cache,(byte*) exchange->line_start->ptr(), exchange->line_start->length())) @@ -610,7 +610,7 @@ select_dump::prepare(List<Item> &list __attribute__((unused))) bool select_dump::send_data(List<Item> &items) { - List_iterator<Item> li(items); + List_iterator_fast<Item> li(items); char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff)),*res; tmp.length(0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 3d218a06d0c..085ea3d7b34 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -23,8 +23,10 @@ class Query_log_event; class Load_log_event; +class Slave_log_event; - +enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; +enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE }; enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN }; @@ -61,11 +63,17 @@ class MYSQL_LOG { char time_buff[20],db[NAME_LEN+1]; char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN]; bool write_error,inited; + uint32 log_seq; // current event sequence number + // needed this for binlog + uint file_id; // current file sequence number for load data infile + // binary logging bool no_rotate; // for binlog - if log name can never change // we should not try to rotate it or write any rotation events // the user should use FLUSH MASTER instead of FLUSH LOGS for // purging + friend class Log_event; + public: MYSQL_LOG(); ~MYSQL_LOG(); @@ -80,8 +88,7 @@ public: bool write(THD *thd, enum enum_server_command command,const char *format,...); bool write(THD *thd, const char *query, uint query_length, time_t query_start=0); - bool write(Query_log_event* event_info); // binary log write - bool write(Load_log_event* event_info); + bool write(Log_event* event_info); // binary log write bool write(IO_CACHE *cache); int generate_new_name(char *new_name,const char *old_name); void make_log_name(char* buf, const char* log_ident); @@ -94,6 +101,7 @@ public: int find_first_log(LOG_INFO* linfo, const char* log_name); int find_next_log(LOG_INFO* linfo); int get_current_log(LOG_INFO* linfo); + uint next_file_id(); inline bool is_open() { return log_type != LOG_CLOSED; } char* get_index_fname() { return index_file_name;} @@ -231,18 +239,18 @@ public: struct rand_struct rand; char *query,*thread_stack; char *host,*user,*priv_user,*db,*ip; - const char *proc_info; + const char *proc_info, *host_or_ip; uint client_capabilities,sql_mode,max_packet_length; uint master_access,db_access; - TABLE *open_tables,*temporary_tables; + TABLE *open_tables,*temporary_tables, *handler_tables; MYSQL_LOCK *lock,*locked_tables; ULL *ull; struct st_my_thread_var *mysys_var; enum enum_server_command command; uint32 server_id; + uint32 log_seq; + uint32 file_id; // for LOAD DATA INFILE const char *where; - char* last_nx_table; // last non-existent table, we need this for replication - char* last_nx_db; // database of the last nx table time_t start_time,time_after_lock,user_time; time_t connect_time,thr_create_time; // track down slow pthread_create thr_lock_type update_lock_default; @@ -256,7 +264,7 @@ public: #ifdef HAVE_GEMINI_DB struct st_gemini gemini; #endif - Item *free_list; + Item *free_list, *handler_items; CONVERT *convert_set; Field *dupp_field; #ifndef __WIN__ @@ -266,7 +274,7 @@ public: Vio* active_vio; pthread_mutex_t active_vio_lock; #endif - ulonglong next_insert_id,last_insert_id,current_insert_id; + ulonglong next_insert_id,last_insert_id,current_insert_id, limit_found_rows; ha_rows select_limit,offset_limit,default_select_limit,cuted_fields, max_join_size, sent_row_count, examined_row_count; table_map used_tables; @@ -293,6 +301,8 @@ public: ulong slave_proxy_id; // in slave thread we need to know in behalf of which // thread the query is being run to replicate temp tables properly + NET* slave_net; // network connection from slave to master + THD(); ~THD(); void cleanup(void); @@ -355,6 +365,10 @@ public: } return last_insert_id; } + inline ulonglong found_rows(void) + { + return limit_found_rows; + } inline bool active_transaction() { #ifdef USING_TRANSACTIONS @@ -399,6 +413,10 @@ public: ** This is used to get result from a select */ +class JOIN; + +void send_error(NET *net,uint sql_errno=0, const char *err=0); + class select_result :public Sql_alloc { protected: THD *thd; @@ -408,7 +426,11 @@ public: virtual int prepare(List<Item> &list) { return 0; } virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_data(List<Item> &items)=0; - virtual void send_error(uint errcode,const char *err)=0; + virtual void initialize_tables (JOIN *join=0) {} + virtual void send_error(uint errcode,const char *err) + { + ::send_error(&thd->net,errcode,err); + } virtual bool send_eof()=0; virtual void abort() {} }; @@ -419,7 +441,6 @@ public: select_send() {} bool send_fields(List<Item> &list,uint flag); bool send_data(List<Item> &items); - void send_error(uint errcode,const char *err); bool send_eof(); }; @@ -443,6 +464,7 @@ public: bool send_eof(); }; + class select_dump :public select_result { sql_exchange *exchange; File file; @@ -463,29 +485,28 @@ public: class select_insert :public select_result { - protected: + public: TABLE *table; List<Item> *fields; - uint save_time_stamp; ulonglong last_insert_id; COPY_INFO info; + uint save_time_stamp; -public: select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic) - :table(table_par),fields(fields_par), save_time_stamp(0),last_insert_id(0) - { - bzero((char*) &info,sizeof(info)); - info.handle_duplicates=duplic; - } + :table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) { + bzero((char*) &info,sizeof(info)); + info.handle_duplicates=duplic; + } ~select_insert(); int prepare(List<Item> &list); - bool send_fields(List<Item> &list, - uint flag) { return 0; } + bool send_fields(List<Item> &list, uint flag) + { return 0; } bool send_data(List<Item> &items); void send_error(uint errcode,const char *err); bool send_eof(); }; + class select_create: public select_insert { ORDER *group; const char *db; @@ -512,6 +533,22 @@ public: void abort(); }; +class select_union :public select_result { + public: + TABLE *table; + COPY_INFO info; + uint save_time_stamp; + + select_union(TABLE *table_par); + ~select_union(); + int prepare(List<Item> &list); + bool send_fields(List<Item> &list, uint flag) + { return 0; } + bool send_data(List<Item> &items); + bool send_eof(); + bool flush(); +}; + /* Structs used when sorting */ typedef struct st_sort_field { @@ -561,3 +598,61 @@ class user_var_entry Item_result type; }; +/* Class for unique (removing of duplicates) */ + +class Unique :public Sql_alloc +{ + DYNAMIC_ARRAY file_ptrs; + ulong max_elements, max_in_memory_size; + IO_CACHE file; + TREE tree; + char *record_pointers; + bool flush(); + +public: + ulong elements; + Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, + uint size, ulong max_in_memory_size_arg); + ~Unique(); + inline bool unique_add(gptr ptr) + { + if (tree.elements_in_tree > max_elements && flush()) + return 1; + return !tree_insert(&tree,ptr,0); + } + + bool get(TABLE *table); + + friend int unique_write_to_file(gptr key, element_count count, Unique *unique); + friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique); +}; + + class multi_delete : public select_result { + TABLE_LIST *delete_tables, *table_being_deleted; +#ifdef SINISAS_STRIP + IO_CACHE **tempfiles; + byte *memory_lane; +#else + Unique **tempfiles; +#endif + THD *thd; + ha_rows deleted; + uint num_of_tables; + int error; + thr_lock_type lock_option; + bool do_delete; + public: + multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg, + uint num_of_tables); + ~multi_delete(); + int prepare(List<Item> &list); + bool send_fields(List<Item> &list, + uint flag) { return 0; } + bool send_data(List<Item> &items); + void initialize_tables (JOIN *join); + void send_error(uint errcode,const char *err); + int do_deletes (bool from_send_error); + bool send_eof(); + }; + + diff --git a/sql/sql_db.cc b/sql/sql_db.cc index d0300b57bdb..520c6c7e94d 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -25,45 +25,28 @@ #include <direct.h> #endif -static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *path, +static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, + const char *db, const char *path, uint level); /* db-name is already validated when we come here */ -void mysql_create_db(THD *thd, char *db, uint create_options) +int mysql_create_db(THD *thd, char *db, uint create_options) { char path[FN_REFLEN+16]; MY_DIR *dirp; long result=1; + int error = 0; DBUG_ENTER("mysql_create_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); - VOID(pthread_mutex_lock(&LOCK_open)); // do not create database if another thread is holding read lock - if (global_read_lock) + if (wait_if_global_read_lock(thd,0)) { - if (thd->global_read_lock) - { - net_printf(&thd->net, ER_CREATE_DB_WITH_READ_LOCK); - VOID(pthread_mutex_unlock(&LOCK_open)); - goto exit; - } - while (global_read_lock && ! thd->killed) - { - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - } - - if (thd->killed) - { - net_printf(&thd->net, ER_SERVER_SHUTDOWN); - VOID(pthread_mutex_unlock(&LOCK_open)); - goto exit; - } - + error= -1; + goto exit2; } - - VOID(pthread_mutex_unlock(&LOCK_open)); /* Check directory */ (void)sprintf(path,"%s/%s", mysql_data_home, db); @@ -73,7 +56,9 @@ void mysql_create_db(THD *thd, char *db, uint create_options) my_dirend(dirp); if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS)) { - net_printf(&thd->net,ER_DB_CREATE_EXISTS,db); + if (thd) + net_printf(&thd->net,ER_DB_CREATE_EXISTS,db); + error = 1; goto exit; } result = 0; @@ -83,72 +68,77 @@ void mysql_create_db(THD *thd, char *db, uint create_options) strend(path)[-1]=0; // Remove last '/' from path if (my_mkdir(path,0777,MYF(0)) < 0) { - net_printf(&thd->net,ER_CANT_CREATE_DB,db,my_errno); + if (thd) + net_printf(&thd->net,ER_CANT_CREATE_DB,db,my_errno); + error = 1; goto exit; } } - if (!thd->query) - { - thd->query = path; - thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)- - path); - } + + if (thd) { - mysql_update_log.write(thd,thd->query, thd->query_length); - if (mysql_bin_log.is_open()) + if (!thd->query) { - Query_log_event qinfo(thd, thd->query); - mysql_bin_log.write(&qinfo); + thd->query = path; + thd->query_length = (uint) (strxmov(path,"create database ", db, NullS)- + path); } + { + mysql_update_log.write(thd,thd->query, thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query); + mysql_bin_log.write(&qinfo); + } + } + if (thd->query == path) + { + thd->query = 0; // just in case + thd->query_length = 0; + } + send_ok(&thd->net, result); } - if (thd->query == path) - { - thd->query = 0; // just in case - thd->query_length = 0; - } - send_ok(&thd->net, result); exit: + start_waiting_global_read_lock(thd); +exit2: VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } -const char *del_exts[]= -{".frm",".ISM",".ISD",".ISM",".HSH",".DAT",".MRG",".MYI",".MYD", ".db", ".BAK", NullS}; +const char *del_exts[]= {".frm", ".BAK", NullS}; static TYPELIB deletable_extentions= {array_elements(del_exts)-1,"del_exts", del_exts}; +const char *known_exts[]= +{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD", ".db", NullS}; +static TYPELIB known_extentions= +{array_elements(del_exts)-1,"del_exts", known_exts}; -/* db-name is already validated when we come here */ +/* + Drop all tables in a database. -void mysql_rm_db(THD *thd,char *db,bool if_exists) + db-name is already validated when we come here + If thd == 0, do not write any messages; This is useful in replication + when we want to remove a stale database before replacing it with the new one +*/ + + +int mysql_rm_db(THD *thd,char *db,bool if_exists) { long deleted=0; + int error = 0; char path[FN_REFLEN+16]; MY_DIR *dirp; DBUG_ENTER("mysql_rm_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); - VOID(pthread_mutex_lock(&LOCK_open)); // do not drop database if another thread is holding read lock - if (global_read_lock) + if (wait_if_global_read_lock(thd,0)) { - if (thd->global_read_lock) - { - net_printf(&thd->net, ER_DROP_DB_WITH_READ_LOCK); - goto exit; - } - while (global_read_lock && ! thd->killed) - { - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - } - - if (thd->killed) - { - net_printf(&thd->net, ER_SERVER_SHUTDOWN); - goto exit; - } + error= -1; + goto exit2; } (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -156,15 +146,20 @@ void mysql_rm_db(THD *thd,char *db,bool if_exists) /* See if the directory exists */ if (!(dirp = my_dir(path,MYF(MY_WME | MY_DONT_SORT)))) { - if (!if_exists) - net_printf(&thd->net,ER_DB_DROP_EXISTS,db); - else - send_ok(&thd->net,0); + if (thd) + { + if (!if_exists) + net_printf(&thd->net,ER_DB_DROP_EXISTS,db); + else + send_ok(&thd->net,0); + } + error = !if_exists; goto exit; } remove_db_from_cache(db); - if ((deleted=mysql_rm_known_files(thd, dirp, path,0)) >= 0) + error = -1; + if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd) { if (!thd->query) { @@ -184,28 +179,34 @@ void mysql_rm_db(THD *thd,char *db,bool if_exists) thd->query_length = 0; } send_ok(&thd->net,(ulong) deleted); + error = 0; } exit: - VOID(pthread_mutex_unlock(&LOCK_open)); + start_waiting_global_read_lock(thd); +exit2: VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); - DBUG_VOID_RETURN; + + DBUG_RETURN(error); } /* Removes files with known extensions plus all found subdirectories that are 2 digits (raid directories). + thd MUST be set when calling this function! */ -static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path, - uint level) +static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, + const char *org_path, uint level) { long deleted=0; ulong found_other_files=0; char filePath[FN_REFLEN]; + TABLE_LIST *tot_list=0, **tot_list_next; DBUG_ENTER("mysql_rm_known_files"); DBUG_PRINT("enter",("path: %s", org_path)); - /* remove all files with known extensions */ + + tot_list_next= &tot_list; for (uint idx=2 ; idx < (uint) dirp->number_off_files && !thd->killed ; @@ -225,7 +226,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path, if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) { DBUG_PRINT("my",("New subdir found: %s", newpath)); - if ((mysql_rm_known_files(thd,new_dirp,newpath,1)) < 0) + if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0) { my_dirend(dirp); DBUG_RETURN(-1); @@ -235,27 +236,44 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path, } if (find_type(fn_ext(file->name),&deletable_extentions,1+2) <= 0) { - found_other_files++; + if (find_type(fn_ext(file->name),&known_extentions,1+2) <= 0) + found_other_files++; continue; } strxmov(filePath,org_path,"/",file->name,NullS); - unpack_filename(filePath,filePath); - if (my_delete(filePath,MYF(MY_WME))) + if (db && !strcasecmp(fn_ext(file->name), reg_ext)) { - net_printf(&thd->net,ER_DB_DROP_DELETE,filePath,my_error); - my_dirend(dirp); - DBUG_RETURN(-1); + /* Drop the table nicely */ + *fn_ext(file->name)=0; // Remove extension + TABLE_LIST *table_list=(TABLE_LIST*) + thd->calloc(sizeof(*table_list)+ strlen(db)+strlen(file->name)+1); + if (!table_list) + { + my_dirend(dirp); + DBUG_RETURN(-1); + } + table_list->db= (char*) (table_list+1); + strmov(table_list->real_name=strmov(table_list->db,db)+1, + file->name); + /* Link into list */ + (*tot_list_next)= table_list; + tot_list_next= &table_list->next; } - deleted++; - } + else + { + if (my_delete_with_symlink(filePath,MYF(MY_WME))) + { + my_dirend(dirp); + DBUG_RETURN(-1); + } + deleted++; + } + } my_dirend(dirp); - if (thd->killed) - { - send_error(&thd->net,ER_SERVER_SHUTDOWN); + if (thd->killed || (tot_list && mysql_rm_table_part2(thd, tot_list, 1, 1))) DBUG_RETURN(-1); - } /* If the directory is a symbolic link, remove the link first, then @@ -275,20 +293,19 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *org_path, /* Don't give errors if we can't delete 'RAID' directory */ if (level) DBUG_RETURN(deleted); - send_error(&thd->net); DBUG_RETURN(-1); } path=filePath; } #endif - /* Remove last FN_LIBCHAR to not cause a probelm on OS/2 */ + /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */ char *pos=strend(path); if (pos > path && pos[-1] == FN_LIBCHAR) *--pos=0; /* Don't give errors if we can't delete 'RAID' directory */ if (rmdir(path) < 0 && !level) { - net_printf(&thd->net,ER_DB_DROP_RMDIR, path,errno); + my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno); DBUG_RETURN(-1); } } @@ -327,11 +344,11 @@ bool mysql_change_db(THD *thd,const char *name) { net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host ? thd->host : thd->ip ? thd->ip : "unknown", + thd->host_or_ip, dbname); mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), thd->priv_user, - thd->host ? thd->host : thd->ip ? thd->ip : "unknown", + thd->host_or_ip, dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index af658ad0346..afaa310cbfb 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB 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 @@ -15,119 +15,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Delete of records */ - -#include "mysql_priv.h" -#include "ha_innobase.h" - /* - Optimize delete of all rows by doing a full generate of the table - This will work even if the .ISM and .ISD tables are destroyed -*/ + Delete of records and truncate of tables. -int generate_table(THD *thd, TABLE_LIST *table_list, TABLE *locked_table) -{ - char path[FN_REFLEN]; - int error; - TABLE **table_ptr; - DBUG_ENTER("generate_table"); - - thd->proc_info="generate_table"; + Multi-table deletes were introduced by Monty and Sinisa +*/ - if (global_read_lock) - { - if(thd->global_read_lock) - { - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0), - table_list->real_name); - DBUG_RETURN(-1); - } - pthread_mutex_lock(&LOCK_open); - while (global_read_lock && ! thd->killed || - thd->version != refresh_version) - { - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - } - pthread_mutex_unlock(&LOCK_open); - } - - /* If it is a temporary table, close and regenerate it */ - if ((table_ptr=find_temporary_table(thd,table_list->db, - table_list->real_name))) - { - TABLE *table= *table_ptr; - HA_CREATE_INFO create_info; - table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); - bzero((char*) &create_info,sizeof(create_info)); - create_info.auto_increment_value= table->file->auto_increment_value; - db_type table_type=table->db_type; - - strmov(path,table->path); - *table_ptr= table->next; // Unlink table from list - close_temporary(table,0); - *fn_ext(path)=0; // Remove the .frm extension - ha_create_table(path, &create_info,1); - if ((error= (int) !(open_temporary_table(thd, path, table_list->db, - table_list->real_name, 1)))) - { - (void) rm_temporary_table(table_type, path); - } - } - else - { - (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db, - table_list->real_name,reg_ext); - fn_format(path,path,"","",4); - VOID(pthread_mutex_lock(&LOCK_open)); - if (locked_table) - mysql_lock_abort(thd,locked_table); // end threads waiting on lock - // close all copies in use - if (remove_table_from_cache(thd,table_list->db,table_list->real_name)) - { - if (!locked_table) - { - VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_RETURN(1); // We must get a lock on table - } - } - if (locked_table) - locked_table->file->extra(HA_EXTRA_FORCE_REOPEN); - if (thd->locked_tables) - close_data_tables(thd,table_list->db,table_list->real_name); - else - close_thread_tables(thd,1); - HA_CREATE_INFO create_info; - bzero((char*) &create_info,sizeof(create_info)); - *fn_ext(path)=0; // Remove the .frm extension - error= ha_create_table(path,&create_info,1) ? -1 : 0; - if (thd->locked_tables && reopen_tables(thd,1,0)) - error= -1; - VOID(pthread_mutex_unlock(&LOCK_open)); - } - if (!error) - { - mysql_update_log.write(thd,thd->query,thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query); - mysql_bin_log.write(&qinfo); - } - send_ok(&thd->net); // This should return record count - } - DBUG_RETURN(error ? -1 : 0); -} +#include "mysql_priv.h" +#include "ha_innobase.h" +#include "sql_select.h" -int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, - thr_lock_type lock_type, ulong options) +int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, + ha_rows limit, thr_lock_type lock_type, ulong options) { int error; TABLE *table; - SQL_SELECT *select; + SQL_SELECT *select=0; READ_RECORD info; bool using_limit=limit != HA_POS_ERROR; - bool use_generate_table,using_transactions; + bool using_transactions; + ha_rows deleted; DBUG_ENTER("mysql_delete"); if (!table_list->db) @@ -138,34 +47,33 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, DBUG_RETURN(1); } - use_generate_table= (!using_limit && !conds && - !(specialflag & - (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !(thd->options & - (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))); -#ifdef HAVE_INNOBASE_DB - /* We need to add code to not generate table based on the table type */ - if (!innodb_skip) - use_generate_table=0; // Innodb can't use re-generate table -#endif - if (use_generate_table && ! thd->open_tables) - { - error=generate_table(thd,table_list,(TABLE*) 0); - if (error <= 0) - DBUG_RETURN(error); // Error or ok - } - if (!(table = open_ltable(thd,table_list, - limit != HA_POS_ERROR ? TL_WRITE_LOW_PRIORITY : - lock_type))) + if (!(table = open_ltable(thd,table_list, lock_type))) DBUG_RETURN(-1); table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; - if (use_generate_table) - DBUG_RETURN(generate_table(thd,table_list,table)); table->map=1; if (setup_conds(thd,table_list,&conds)) DBUG_RETURN(-1); + /* Test if the user wants to delete all rows */ + if (!using_limit && (!conds || conds->const_item()) && + !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE))) + { + deleted= table->file->records; + if (!(error=table->file->delete_all_rows())) + { + error= -1; // ok + goto cleanup; + } + if (error != HA_ERR_WRONG_COMMAND) + { + table->file->print_error(error,MYF(0)); + error=0; + goto cleanup; + } + /* Handler didn't support fast delete; Delete rows one by one */ + } + table->used_keys=table->quick_keys=0; // Can't use 'only index' select=make_select(table,0,0,conds,&error); if (error) @@ -182,7 +90,7 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, /* If running in safe sql mode, don't allow updates without keys */ if (!table->quick_keys) { - thd->lex.options|=QUERY_NO_INDEX_USED; + thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR) { delete select; @@ -192,9 +100,36 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, } (void) table->file->extra(HA_EXTRA_NO_READCHECK); if (options & OPTION_QUICK) - (void) table->file->extra(HA_EXTRA_QUICK); - init_read_record(&info,thd,table,select,-1,1); - ulong deleted=0L; + (void) table->file->extra(HA_EXTRA_QUICK); + + if (order) + { + uint length; + SORT_FIELD *sortorder; + TABLE_LIST tables; + List<Item> fields; + List<Item> all_fields; + ha_rows examined_rows; + + bzero((char*) &tables,sizeof(tables)); + tables.table = table; + + table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + if (setup_order(thd, &tables, fields, all_fields, order) || + !(sortorder=make_unireg_sortorder(order, &length)) || + (table->found_records = filesort(table, sortorder, length, + (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + &examined_rows)) + == HA_POS_ERROR) + { + delete select; + DBUG_RETURN(-1); // This will force out message + } + } + + init_read_record(&info,thd,table,select,1,1); + deleted=0L; thd->proc_info="updating"; while (!(error=info.read_record(&info)) && !thd->killed) { @@ -221,9 +156,12 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, } thd->proc_info="end"; end_read_record(&info); + /* if (order) free_io_cache(table); */ /* QQ Should not be needed */ (void) table->file->extra(HA_EXTRA_READCHECK); if (options & OPTION_QUICK) - (void) table->file->extra(HA_EXTRA_NORMAL); + (void) table->file->extra(HA_EXTRA_NORMAL); + +cleanup: using_transactions=table->file->has_transactions(); if (deleted && (error <= 0 || !using_transactions)) { @@ -256,3 +194,374 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit, } +/*************************************************************************** +** delete multiple tables from join +***************************************************************************/ + +#define MEM_STRIP_BUF_SIZE sortbuff_size + +int refposcmp2(void* arg, const void *a,const void *b) +{ + return memcmp(a,b, *(int*) arg); +} + +multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, + thr_lock_type lock_option_arg, + uint num_of_tables_arg) + : delete_tables (dt), thd(thd_arg), deleted(0), + num_of_tables(num_of_tables_arg), error(0), lock_option(lock_option_arg), + do_delete(false) +{ + uint counter=0; + tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1)); + + (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK); + /* Don't use key read with MULTI-TABLE-DELETE */ + (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD); + dt->table->used_keys=0; + for (dt=dt->next ; dt ; dt=dt->next,counter++) + { + TABLE *table=dt->table; + (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK); + (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD); + tempfiles[counter] = new Unique (refposcmp2, + (void *) &table->file->ref_length, + table->file->ref_length, + MEM_STRIP_BUF_SIZE); + } +} + + +int +multi_delete::prepare(List<Item> &values) +{ + DBUG_ENTER("multi_delete::prepare"); + do_delete = true; + thd->proc_info="deleting from main table"; + + if (thd->options & OPTION_SAFE_UPDATES) + { + TABLE_LIST *table_ref; + for (table_ref=delete_tables; table_ref; table_ref=table_ref->next) + { + TABLE *table=table_ref->table; + if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys) + { + my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); + DBUG_RETURN(1); + } + } + } + DBUG_RETURN(0); +} + + +void +multi_delete::initialize_tables(JOIN *join) +{ + TABLE_LIST *walk; + table_map tables_to_delete_from=0; + for (walk= delete_tables ; walk ; walk=walk->next) + tables_to_delete_from|= walk->table->map; + + walk= delete_tables; + for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; + tab < end; + tab++) + { + if (tab->table->map & tables_to_delete_from) + { + /* We are going to delete from this table */ + walk->table=tab->table; + walk=walk->next; + } + } +} + + +multi_delete::~multi_delete() +{ + /* Add back EXTRA_READCHECK; In 4.0.1 we shouldn't need this anymore */ + for (table_being_deleted=delete_tables ; + table_being_deleted ; + table_being_deleted=table_being_deleted->next) + (void) table_being_deleted->table->file->extra(HA_EXTRA_READCHECK); + + for (uint counter = 0; counter < num_of_tables-1; counter++) + { + if (tempfiles[counter]) + delete tempfiles[counter]; + } +} + + +bool multi_delete::send_data(List<Item> &values) +{ + int secure_counter= -1; + for (table_being_deleted=delete_tables ; + table_being_deleted ; + table_being_deleted=table_being_deleted->next, secure_counter++) + { + TABLE *table=table_being_deleted->table; + + /* Check if we are using outer join and we didn't find the row */ + if (table->status & (STATUS_NULL_ROW | STATUS_DELETED)) + continue; + + table->file->position(table->record[0]); + int rl = table->file->ref_length; + + if (secure_counter < 0) + { + table->status|= STATUS_DELETED; + if (!(error=table->file->delete_row(table->record[0]))) + deleted++; + else + { + table->file->print_error(error,MYF(0)); + return 1; + } + } + else + { + error=tempfiles[secure_counter]->unique_add(table->file->ref); + if (error) + { + error=-1; + return 1; + } + } + } + return 0; +} + + + +/* Return true if some table is not transaction safe */ + +static bool some_table_is_not_transaction_safe (TABLE_LIST *tl) +{ + for (; tl ; tl=tl->next) + { + if (!(tl->table->file->has_transactions())) + return true; + } + return false; +} + + +void multi_delete::send_error(uint errcode,const char *err) +{ + /* First send error what ever it is ... */ + ::send_error(&thd->net,errcode,err); + /* If nothing deleted return */ + if (!deleted) + return; + /* Below can happen when thread is killed early ... */ + if (!table_being_deleted) + table_being_deleted=delete_tables; + + /* + If rows from the first table only has been deleted and it is transactional, + just do rollback. + The same if all tables are transactional, regardless of where we are. + In all other cases do attempt deletes ... + */ + if ((table_being_deleted->table->file->has_transactions() && + table_being_deleted == delete_tables) || + !some_table_is_not_transaction_safe(delete_tables->next)) + ha_rollback(thd); + else if (do_delete) + VOID(do_deletes(true)); +} + + +int multi_delete::do_deletes (bool from_send_error) +{ + int error = 0, counter = 0, count; + + if (from_send_error) + { + /* Found out table number for 'table_being_deleted' */ + for (TABLE_LIST *aux=delete_tables; + aux != table_being_deleted; + aux=aux->next) + counter++; + } + else + table_being_deleted = delete_tables; + + do_delete = false; + for (table_being_deleted=table_being_deleted->next; + table_being_deleted ; + table_being_deleted=table_being_deleted->next, counter++) + { + TABLE *table = table_being_deleted->table; + int rl = table->file->ref_length; + if (tempfiles[counter]->get(table)) + { + error=1; + break; + } + +#if USE_REGENERATE_TABLE + // nice little optimization .... + // but Monty has to fix generate_table... + // This will not work for transactional tables because for other types + // records is not absolute + if (num_of_positions == table->file->records) + { + TABLE_LIST table_list; + bzero((char*) &table_list,sizeof(table_list)); + table_list.name=table->table_name; table_list.real_name=table_being_deleted->real_name; + table_list.table=table; + table_list.grant=table->grant; + table_list.db = table_being_deleted->db; + error=generate_table(thd,&table_list,(TABLE *)0); + if (error <= 0) {error = 1; break;} + deleted += num_of_positions; + continue; + } +#endif /* USE_REGENERATE_TABLE */ + + READ_RECORD info; + error=0; + init_read_record(&info,thd,table,NULL,0,0); + bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables); + while (!(error=info.read_record(&info)) && + (!thd->killed || from_send_error || not_trans_safe)) + { + error=table->file->delete_row(table->record[0]); + if (error) + { + table->file->print_error(error,MYF(0)); + break; + } + else + deleted++; + } + end_read_record(&info); + if (error == -1) + error = 0; + } + return error; +} + + +bool multi_delete::send_eof() +{ + thd->proc_info="deleting from reference tables"; + int error = do_deletes(false); + + thd->proc_info="end"; + if (error && error != -1) + { + ::send_error(&thd->net); + return 1; + } + + if (deleted && + (error <= 0 || some_table_is_not_transaction_safe(delete_tables))) + { + mysql_update_log.write(thd,thd->query,thd->query_length); + Query_log_event qinfo(thd, thd->query); + if (mysql_bin_log.write(&qinfo) && + !some_table_is_not_transaction_safe(delete_tables)) + error=1; // Rollback + VOID(ha_autocommit_or_rollback(thd,error >= 0)); + } + ::send_ok(&thd->net,deleted); + return 0; +} + + +/*************************************************************************** +* TRUNCATE TABLE +****************************************************************************/ + +/* + Optimize delete of all rows by doing a full generate of the table + This will work even if the .ISM and .ISD tables are destroyed + + dont_send_ok should be set if: + - We should always wants to generate the table (even if the table type + normally can't safely do this. + - We don't want an ok to be sent to the end user. + - We don't want to log the truncate command + - If we want to have a name lock on the table on exit without errors. +*/ + +int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) +{ + HA_CREATE_INFO create_info; + char path[FN_REFLEN]; + TABLE **table_ptr; + int error; + DBUG_ENTER("mysql_truncate"); + + /* If it is a temporary table, close and regenerate it */ + if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db, + table_list->real_name))) + { + TABLE *table= *table_ptr; + HA_CREATE_INFO create_info; + table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); + bzero((char*) &create_info,sizeof(create_info)); + create_info.auto_increment_value= table->file->auto_increment_value; + db_type table_type=table->db_type; + + strmov(path,table->path); + *table_ptr= table->next; // Unlink table from list + close_temporary(table,0); + *fn_ext(path)=0; // Remove the .frm extension + ha_create_table(path, &create_info,1); + if ((error= (int) !(open_temporary_table(thd, path, table_list->db, + table_list->real_name, 1)))) + (void) rm_temporary_table(table_type, path); + DBUG_RETURN(error ? -1 : 0); + } + + (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db, + table_list->real_name,reg_ext); + fn_format(path,path,"","",4); + + if (!dont_send_ok) + { + db_type table_type; + if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN) + { + my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } + if (!ha_supports_generate(table_type)) + { + /* Probably InnoDB table */ + DBUG_RETURN(mysql_delete(thd,table_list, (COND*) 0, (ORDER*) 0, + HA_POS_ERROR, TL_WRITE, 0)); + } + if (lock_and_wait_for_table_name(thd, table_list)) + DBUG_RETURN(-1); + } + + bzero((char*) &create_info,sizeof(create_info)); + *fn_ext(path)=0; // Remove the .frm extension + error= ha_create_table(path,&create_info,1) ? -1 : 0; + + if (!dont_send_ok) + { + if (!error) + { + mysql_update_log.write(thd,thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query); + mysql_bin_log.write(&qinfo); + } + send_ok(&thd->net); // This should return record count + } + unlock_table_name(thd, table_list); + } + else if (error) + unlock_table_name(thd, table_list); + DBUG_RETURN(error ? -1 : 0); +} diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc new file mode 100644 index 00000000000..98cc523dc9b --- /dev/null +++ b/sql/sql_handler.cc @@ -0,0 +1,254 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + + +/* HANDLER ... commands - direct access to ISAM */ + +#include <assert.h> +#include "mysql_priv.h" +#include "sql_select.h" + +/* TODO: + HANDLER blabla OPEN [ AS foobar ] [ (column-list) ] + + the most natural (easiest, fastest) way to do it is to + compute List<Item> field_list not in mysql_ha_read + but in mysql_ha_open, and then store it in TABLE structure. + + The problem here is that mysql_parse calls free_item to free all the + items allocated at the end of every query. The workaround would to + keep two item lists per THD - normal free_list and handler_items. + The second is to be freeed only on thread end. mysql_ha_open should + then do { handler_items=concat(handler_items, free_list); free_list=0; } + + But !!! do_cammand calls free_root at the end of every query and frees up + all the sql_alloc'ed memory. It's harder to work around... + */ + +#define HANDLER_TABLES_HACK(thd) { \ + TABLE *tmp=thd->open_tables; \ + thd->open_tables=thd->handler_tables; \ + thd->handler_tables=tmp; } + +static TABLE **find_table_ptr_by_name(THD *thd, const char *db, + const char *table_name); + +int mysql_ha_open(THD *thd, TABLE_LIST *tables) +{ + HANDLER_TABLES_HACK(thd); + int err=open_tables(thd,tables); + HANDLER_TABLES_HACK(thd); + if (err) + return -1; + + send_ok(&thd->net); + return 0; +} + +int mysql_ha_close(THD *thd, TABLE_LIST *tables) +{ + TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->name); + + if (*ptr) + close_thread_table(thd, ptr); + + send_ok(&thd->net); + return 0; +} + +static enum enum_ha_read_modes rkey_to_rnext[]= + { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV }; + +int mysql_ha_read(THD *thd, TABLE_LIST *tables, + enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr, + enum ha_rkey_function ha_rkey_mode, Item *cond, + ha_rows select_limit,ha_rows offset_limit) +{ + int err, keyno=-1; + TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->name); + if (!table) + { + my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0), + tables->name,"HANDLER"); + return -1; + } + tables->table=table; + + if (cond && cond->fix_fields(thd,tables)) + return -1; + + if (keyname) + { + if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) + { + my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0), + keyname,tables->name); + return -1; + } + } + + List<Item> list; + list.push_front(new Item_field(NULL,NULL,"*")); + List_iterator<Item> it(list); + it++; + + insert_fields(thd,tables,tables->db,tables->name,&it); + + table->file->index_init(keyno); + + select_limit+=offset_limit; + send_fields(thd,list,1); + + MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1); + + for (uint num_rows=0; num_rows < select_limit; ) + { + switch(mode) + { + case RFIRST: + err=keyname ? + table->file->index_first(table->record[0]) : + table->file->rnd_init(1) || + table->file->rnd_next(table->record[0]); + mode=RNEXT; + break; + case RLAST: + dbug_assert(keyname != 0); + err=table->file->index_last(table->record[0]); + mode=RPREV; + break; + case RNEXT: + err=keyname ? + table->file->index_next(table->record[0]) : + table->file->rnd_next(table->record[0]); + break; + case RPREV: + dbug_assert(keyname != 0); + err=table->file->index_prev(table->record[0]); + break; + case RKEY: + { + dbug_assert(keyname != 0); + KEY *keyinfo=table->key_info+keyno; + KEY_PART_INFO *key_part=keyinfo->key_part; + uint key_len; + byte *key; + if (key_expr->elements > keyinfo->key_parts) + { + my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS), + MYF(0),keyinfo->key_parts); + goto err; + } + List_iterator_fast<Item> it_ke(*key_expr); + Item *item; + for (key_len=0 ; (item=it_ke++) ; key_part++) + { + item->save_in_field(key_part->field); + key_len+=key_part->store_length; + } + if (!(key=sql_calloc(ALIGN_SIZE(key_len)))) + { + send_error(&thd->net,ER_OUTOFMEMORY); + goto err; + } + key_copy(key, table, keyno, key_len); + err=table->file->index_read(table->record[0], + key,key_len,ha_rkey_mode); + mode=rkey_to_rnext[(int)ha_rkey_mode]; + break; + } + default: + send_error(&thd->net,ER_ILLEGAL_HA); + goto err; + } + + if (err) + { + if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE) + { + sql_print_error("mysql_ha_read: Got error %d when reading table", + err); + table->file->print_error(err,MYF(0)); + goto err; + } + goto ok; + } + if (cond) + { + err=err; + if(!cond->val_int()) + continue; + } + if (num_rows>=offset_limit) + { + if (!err) + { + String *packet = &thd->packet; + Item *item; + packet->length(0); + it.rewind(); + while ((item=it++)) + { + if (item->send(packet)) + { + packet->free(); // Free used + my_error(ER_OUT_OF_RESOURCES,MYF(0)); + goto err; + } + } + my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); + } + } + num_rows++; + } +ok: + mysql_unlock_tables(thd,lock); + send_eof(&thd->net); + return 0; +err: + mysql_unlock_tables(thd,lock); + return -1; +} + +/************************************************************************** + 2Monty: It could easily happen, that the following service functions are + already defined somewhere in the code, but I failed to find them. + If this is the case, just say a word and I'll use old functions here. +**************************************************************************/ + +/* Note: this function differs from find_locked_table() because we're looking + here for alias, not real table name + */ +static TABLE **find_table_ptr_by_name(THD *thd, const char *db, + const char *table_name) +{ + int dblen; + TABLE **ptr; + + if (!db || ! *db) + db= thd->db ? thd->db : ""; + dblen=strlen(db)+1; + ptr=&(thd->handler_tables); + + for (TABLE *table=*ptr; table ; table=*ptr) + { + if (!memcmp(table->table_cache_key, db, dblen) && + !my_strcasecmp(table->table_name,table_name)) + break; + ptr=&(table->next); + } + return ptr; +} diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cd738999383..1d2805d8e90 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -78,7 +78,8 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, table_list.grant=table->grant; thd->dupp_field=0; - if (setup_tables(&table_list) || setup_fields(thd,&table_list,fields,1,0)) + if (setup_tables(&table_list) || + setup_fields(thd,&table_list,fields,1,0,0)) return -1; if (thd->dupp_field) { @@ -102,14 +103,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, int error; bool log_on= ((thd->options & OPTION_UPDATE_LOG) || !(thd->master_access & PROCESS_ACL)); - bool using_transactions; + bool using_transactions, bulk_insert=0; uint value_count; uint save_time_stamp; ulong counter = 1; ulonglong id; COPY_INFO info; TABLE *table; - List_iterator<List_item> its(values_list); + List_iterator_fast<List_item> its(values_list); List_item *values; char *query=thd->query; DBUG_ENTER("mysql_insert"); @@ -151,7 +152,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, save_time_stamp=table->time_stamp; values= its++; if (check_insert_fields(thd,table,fields,*values,1) || - setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0)) + setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0)) { table->time_stamp=save_time_stamp; goto abort; @@ -168,7 +169,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, table->time_stamp=save_time_stamp; goto abort; } - if (setup_fields(thd,table_list,*values,0,0)) + if (setup_fields(thd,table_list,*values,0,0,0)) { table->time_stamp=save_time_stamp; goto abort; @@ -192,6 +193,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, thd->proc_info="update"; if (duplic == DUP_IGNORE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if ((bulk_insert= (values_list.elements > 1 && + lock_type != TL_WRITE_DELAYED && + !(specialflag & SPECIAL_SAFE_MODE)))) + { + table->file->extra(HA_EXTRA_WRITE_CACHE); + table->file->extra(HA_EXTRA_BULK_INSERT_BEGIN); + } + while ((values = its++)) { if (fields.elements || !value_count) @@ -256,6 +265,25 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, } else { + if (bulk_insert) + { + if (table->file->extra(HA_EXTRA_NO_CACHE)) + { + if (!error) + { + table->file->print_error(my_errno,MYF(0)); + error=1; + } + } + if (table->file->extra(HA_EXTRA_BULK_INSERT_END)) + { + if (!error) + { + table->file->print_error(my_errno,MYF(0)); + error=1; + } + } + } if (id && values_list.elements != 1) thd->insert_id(id); // For update log else if (table->next_number_field) @@ -288,7 +316,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, thd->next_insert_id=0; // Reset this if wrongly used if (duplic == DUP_IGNORE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); - if (error) goto abort; @@ -646,7 +673,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) /* Copy error message and abort */ thd->fatal_error=1; strmov(thd->net.last_error,tmp->thd.net.last_error); - thd->net.last_errno=thd->net.last_errno; + thd->net.last_errno=tmp->thd.net.last_errno; } tmp->unlock(); pthread_mutex_unlock(&LOCK_delayed_create); @@ -1241,7 +1268,7 @@ select_insert::prepare(List<Item> &values) restore_record(table,2); // Get empty record table->next_number_field=table->found_next_number_field; - thd->count_cuted_fields=1; /* calc cuted fields */ + thd->count_cuted_fields=1; // calc cuted fields thd->cuted_fields=0; if (info.handle_duplicates != DUP_REPLACE) table->file->extra(HA_EXTRA_WRITE_CACHE); @@ -1393,6 +1420,7 @@ bool select_create::send_data(List<Item> &values) extern HASH open_cache; + bool select_create::send_eof() { bool tmp=select_insert::send_eof(); @@ -1405,7 +1433,8 @@ bool select_create::send_eof() mysql_unlock_tables(thd, lock); if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); - lock=0; table=0; + lock=0; + table=0; VOID(pthread_mutex_unlock(&LOCK_open)); } return tmp; @@ -1437,7 +1466,7 @@ void select_create::abort() *****************************************************************************/ #ifdef __GNUC__ -template class List_iterator<List_item>; +template class List_iterator_fast<List_item>; template class I_List<delayed_insert>; template class I_List_iterator<delayed_insert>; template class I_List<delayed_row>; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e0044a0710f..bfda57a06ad 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -142,11 +142,11 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->next_state=STATE_START; lex->end_of_query=(lex->ptr=buf)+length; lex->yylineno = 1; - lex->create_refs=lex->in_comment=0; + lex->select->create_refs=lex->in_comment=0; lex->length=0; - lex->in_sum_expr=0; - lex->expr_list.empty(); - lex->ftfunc_list.empty(); + lex->select->in_sum_expr=0; + lex->select->expr_list.empty(); + lex->select->ftfunc_list.empty(); lex->convert_set=(lex->thd=thd)->convert_set; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); @@ -155,7 +155,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) void lex_end(LEX *lex) { - lex->expr_list.delete_elements(); // If error when parsing sql-varargs + lex->select->expr_list.delete_elements(); // If error when parsing sql-varargs x_free(lex->yacc_yyss); x_free(lex->yacc_yyvs); } @@ -196,7 +196,7 @@ static int find_keyword(LEX *lex, uint len, bool function) /* make a copy of token before ptr and set yytoklen */ -static inline LEX_STRING get_token(LEX *lex,uint length) +LEX_STRING get_token(LEX *lex,uint length) { LEX_STRING tmp; yyUnget(); // ptr points now after last token char @@ -430,7 +430,7 @@ int yylex(void *arg) switch(state) { case STATE_OPERATOR_OR_IDENT: // Next is operator or keyword case STATE_START: // Start of token - // Skipp startspace + // Skip startspace for (c=yyGet() ; (state_map[c] == STATE_SKIP) ; c= yyGet()) { if (c == '\n') @@ -458,6 +458,11 @@ int yylex(void *arg) return((int) c); case STATE_IDENT: // Incomplete keyword or ident + if ((c == 'x' || c == 'X') && yyPeek() == '\'') + { // Found x'hex-number' + state=STATE_HEX_NUMBER; + break; + } #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(default_charset_info)) { @@ -509,6 +514,8 @@ int yylex(void *arg) yySkip(); // next state does a unget } yylval->lex_str=get_token(lex,length); + if (lex->convert_set) + lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen); return(IDENT); case STATE_IDENT_SEP: // Found ident and now '.' @@ -518,7 +525,7 @@ int yylex(void *arg) c=yyGet(); // should be '.' return((int) c); - case STATE_NUMBER_IDENT: // number or ident which starts with num + case STATE_NUMBER_IDENT: // number or ident which num-start while (isdigit((c = yyGet()))) ; if (state_map[c] != STATE_IDENT) { // Can't be identifier @@ -544,10 +551,10 @@ int yylex(void *arg) lex->tok_start[0] == '0' ) { // Varbinary while (isxdigit((c = yyGet()))) ; - if ((lex->ptr - lex->tok_start) >= 4) + if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT) { yylval->lex_str=get_token(lex,yyLength()); - yylval->lex_str.str+=2; // Skipp 0x + yylval->lex_str.str+=2; // Skip 0x yylval->lex_str.length-=2; lex->yytoklen-=2; return (HEX_NUM); @@ -597,21 +604,26 @@ int yylex(void *arg) case STATE_FOUND_IDENT: // Complete ident yylval->lex_str=get_token(lex,yyLength()); + if (lex->convert_set) + lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen); return(IDENT); case STATE_USER_VARIABLE_DELIMITER: - lex->tok_start=lex->ptr; // Skipp first ` + lex->tok_start=lex->ptr; // Skip first ` while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER && c != (uchar) NAMES_SEP_CHAR) ; yylval->lex_str=get_token(lex,yyLength()); + if (lex->convert_set) + lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen); if (state_map[c] == STATE_USER_VARIABLE_DELIMITER) - yySkip(); // Skipp end ` + yySkip(); // Skip end ` return(IDENT); case STATE_SIGNED_NUMBER: // Incomplete signed number if (prev_state == STATE_OPERATOR_OR_IDENT) { - if (c == '-' && yyPeek() == '-' && isspace(yyPeek2())) + if (c == '-' && yyPeek() == '-' && + (isspace(yyPeek2()) || iscntrl(yyPeek2()))) state=STATE_COMMENT; else state= STATE_CHAR; // Must be operator @@ -651,7 +663,7 @@ int yylex(void *arg) { c = yyGet(); if (c == '-' || c == '+') - c = yyGet(); // Skipp sign + c = yyGet(); // Skip sign if (!isdigit(c)) { // No digit after sign state= STATE_CHAR; @@ -664,6 +676,21 @@ int yylex(void *arg) yylval->lex_str=get_token(lex,yyLength()); return(REAL_NUM); + case STATE_HEX_NUMBER: // Found x'hexstring' + yyGet(); // Skip ' + while (isxdigit((c = yyGet()))) ; + length=(lex->ptr - lex->tok_start); // Length of hexnum+3 + if (!(length & 1) || c != '\'') + { + return(ABORT_SYM); // Illegal hex constant + } + yyGet(); // get_token makes an unget + yylval->lex_str=get_token(lex,length); + yylval->lex_str.str+=2; // Skip x' + yylval->lex_str.length-=3; // Don't count x' and last ' + lex->yytoklen-=3; + return (HEX_NUM); + case STATE_CMP_OP: // Incomplete comparison operator if (state_map[yyPeek()] == STATE_CMP_OP || state_map[yyPeek()] == STATE_LONG_CMP_OP) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 10a99f920bd..4d2441da246 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -53,7 +53,10 @@ enum enum_sql_command { SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS, - SQLCOM_SHOW_OPEN_TABLES + SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, + SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, + SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, + SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, }; enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT, @@ -62,6 +65,7 @@ enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT, STATE_FOUND_IDENT, STATE_SIGNED_NUMBER, STATE_REAL, + STATE_HEX_NUMBER, STATE_CMP_OP, STATE_LONG_CMP_OP, STATE_STRING, @@ -90,42 +94,75 @@ typedef struct st_lex_master_info { char* host, *user, *password,*log_file_name; uint port, connect_retry; + ulong last_log_seq; ulonglong pos; + ulong server_id; } LEX_MASTER_INFO; + +enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE}; + +/* The state of the lex parsing for selects */ + +typedef struct st_select_lex { + enum sub_select_type linkage; + char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */ + Item *where,*having; + ha_rows select_limit,offset_limit; + ulong options; + List<List_item> expr_list; + List<List_item> when_list; + SQL_LIST order_list,table_list,group_list; + List<Item> item_list; + List<String> interval_list,use_index, *use_index_ptr, + ignore_index, *ignore_index_ptr; + List<Item_func_match> ftfunc_list; + uint in_sum_expr, sort_default; + bool create_refs; + st_select_lex *next; +} SELECT_LEX; + + +class Set_option :public Sql_alloc { +public: + const char *name; + Item *item; + uint name_length; + bool type; /* 1 if global */ + Set_option(bool par_type, const char *par_name, uint length, + Item *par_item) + :name(par_name), item(par_item), name_length(length), type(par_type) {} +}; + + /* The state of the lex parsing. This is saved in the THD struct */ typedef struct st_lex { uint yylineno,yytoklen; /* Simulate lex */ LEX_YYSTYPE yylval; + SELECT_LEX select_lex, *select; uchar *ptr,*tok_start,*tok_end,*end_of_query; char *length,*dec,*change,*name; - char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */ char *backup_dir; /* For RESTORE/BACKUP */ char* to_log; /* For PURGE MASTER LOGS TO */ String *wild; sql_exchange *exchange; - ha_rows select_limit,offset_limit; - List<List_item> expr_list; - List<List_item> when_list; - List<List_item> many_values; List<key_part_spec> col_list; List<Alter_drop> drop_list; List<Alter_column> alter_list; - List<String> interval_list,use_index,*use_index_ptr, - ignore_index, *ignore_index_ptr; + List<String> interval_list; List<st_lex_user> users_list; List<LEX_COLUMN> columns; List<Key> key_list; List<create_field> create_list; - List<Item> item_list,*insert_list,field_list,value_list; - List<Item_func_match> ftfunc_list; - SQL_LIST order_list,table_list,group_list,proc_list; + List<Item> *insert_list,field_list,value_list; + List<List_item> many_values; + List<Set_option> option_list; + SQL_LIST proc_list, auxilliary_table_list; TYPELIB *interval; create_field *last_field; - - Item *where,*having,*default_value; + Item *default_value; CONVERT *convert_set; LEX_USER *grant_user; gptr yacc_yyss,yacc_yyvs; @@ -135,16 +172,18 @@ typedef struct st_lex { HA_CREATE_INFO create_info; LEX_MASTER_INFO mi; // used by CHANGE MASTER ulong thread_id,type; - ulong options; ulong gemini_spin_retries; enum_sql_command sql_command; enum lex_states next_state; enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; - uint in_sum_expr,grant,grant_tot_col,which_columns, sort_default; + enum enum_ha_read_modes ha_read_mode; + enum ha_rkey_function ha_rkey_mode; + enum enum_enable_or_disable alter_keys_onoff; + uint grant,grant_tot_col,which_columns, union_option; thr_lock_type lock_option; - bool create_refs,drop_primary,drop_if_exists,local_file; - bool in_comment,ignore_space,verbose; + bool drop_primary,drop_if_exists,local_file; + bool in_comment,ignore_space,verbose,simple_alter, option_type; } LEX; diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 7d5fc442121..be630dfc038 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -20,3 +20,5 @@ #endif #include "mysql_priv.h" + +list_node end_of_list; diff --git a/sql/sql_list.h b/sql/sql_list.h index d21f2e658dc..1e1b3a612e6 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -41,25 +41,40 @@ public: /* ** basic single linked list ** Used for item and item_buffs. +** All list ends with a pointer to the 'end_of_list' element, which +** data pointer is a null pointer and the next pointer points to itself. +** This makes it very fast to traverse lists as we don't have to +** test for a specialend condition for list that can't contain a null +** pointer. */ +class list_node :public Sql_alloc +{ +public: + list_node *next; + void *info; + list_node(void *info_par,list_node *next_par) + :next(next_par),info(info_par) + {} + list_node() /* For end_of_list */ + { + info=0; + next= this; + } + friend class base_list; + friend class base_list_iterator; +}; + +extern list_node end_of_list; + class base_list :public Sql_alloc { protected: - class list_node :public Sql_alloc - { - public: - list_node *next; - void *info; - list_node(void *info_par,list_node *next_par) : next(next_par),info(info_par) {} - friend class base_list; - friend class base_list_iterator; - }; list_node *first,**last; public: uint elements; - inline void empty() { elements=0; first=0; last=&first;} + inline void empty() { elements=0; first= &end_of_list; last=&first;} inline base_list() { empty(); } inline base_list(const base_list &tmp) :Sql_alloc() { @@ -69,7 +84,7 @@ public: } inline bool push_back(void *info) { - if (((*last)=new list_node(info,0))) + if (((*last)=new list_node(info, &end_of_list))) { last= &(*last)->next; elements++; @@ -82,7 +97,7 @@ public: list_node *node=new list_node(info,first); if (node) { - if (!first) + if (last == &first) last= &node->next; first=node; elements++; @@ -96,22 +111,21 @@ public: delete *prev; *prev=node; if (!--elements) - { last= &first; - first=0; - } } inline void *pop(void) { - if (!first) return 0; + if (first == &end_of_list) return 0; list_node *tmp=first; first=first->next; if (!--elements) last= &first; return tmp->info; } - inline void *head() { return first ? first->info : 0; } - inline void **head_ref() { return first ? &first->info : 0; } + inline void *head() { return first->info; } + inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } + inline bool is_empty() { return first == &end_of_list ; } + inline list_node *last_ref() { return &end_of_list; } friend class base_list_iterator; protected: @@ -129,7 +143,7 @@ protected: class base_list_iterator { base_list *list; - base_list::list_node **el,**prev,*current; + list_node **el,**prev,*current; public: base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first), prev(0),current(0) @@ -137,16 +151,22 @@ public: inline void *next(void) { prev=el; - if (!(current= *el)) - return 0; + current= *el; el= ¤t->next; return current->info; } + inline void *next_fast(void) + { + list_node *tmp; + tmp= *el; + el= &tmp->next; + return tmp->info; + } inline void rewind(void) { el= &list->first; } - void *replace(void *element) + inline void *replace(void *element) { // Return old element void *tmp=current->info; current->info=element; @@ -155,7 +175,7 @@ public: void *replace(base_list &new_list) { void *ret_value=current->info; - if (new_list.first) + if (!new_list.is_empty()) { *new_list.last=current->next; current->info=new_list.first->info; @@ -182,7 +202,7 @@ public: } inline bool is_last(void) { - return *el == 0; + return el == &list->last_ref()->next; } }; @@ -200,7 +220,7 @@ public: void delete_elements(void) { list_node *element,*next; - for (element=first; element ; element=next) + for (element=first; element != &end_of_list; element=next) { next=element->next; delete (T*) element->info; @@ -215,13 +235,25 @@ template <class T> class List_iterator :public base_list_iterator public: List_iterator(List<T> &a) : base_list_iterator(a) {} inline T* operator++(int) { return (T*) base_list_iterator::next(); } - inline void rewind(void) { base_list_iterator::rewind(); } inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } - inline void remove(void) { base_list_iterator::remove(); } inline void after(T *a) { base_list_iterator::after(a); } inline T** ref(void) { return (T**) base_list_iterator::ref(); } - inline bool is_last(void) { return base_list_iterator::is_last(); } +}; + +template <class T> class List_iterator_fast :public base_list_iterator +{ +protected: + inline T *replace(T *a) { return (T*) 0; } + inline T *replace(List<T> &a) { return (T*) 0; } + inline void remove(void) { } + inline void after(T *a) { } + inline T** ref(void) { return (T**) 0; } + +public: + List_iterator_fast(List<T> &a) : base_list_iterator(a) {} + inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } + inline void rewind(void) { base_list_iterator::rewind(); } }; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 9d3b899d31b..c2793da78f3 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -20,6 +20,7 @@ #include "mysql_priv.h" #include <my_dir.h> #include <m_ctype.h> +#include "sql_repl.h" class READ_INFO { File file; @@ -32,6 +33,7 @@ class READ_INFO { int field_term_char,line_term_char,enclosed_char,escape_char; int *stack,*stack_pos; bool found_end_of_line,start_of_line,eof; + bool need_end_io_cache; IO_CACHE cache; NET *io_net; @@ -50,6 +52,18 @@ public: char unescape(char chr); int terminator(char *ptr,uint length); bool find_start_of_fields(); + // we need to force cache close before destructor is invoked to log + // the last read block + void end_io_cache() + { + ::end_io_cache(&cache); + need_end_io_cache = 0; + } + + // either this method, or we need to make cache public + // arg must be set from mysql_load() since constructor does not see + // either the table or THD value + void set_io_cache_arg(void* arg) { cache.arg = arg; } }; static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table, @@ -67,12 +81,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, File file; TABLE *table; int error; - uint save_skip_lines = ex->skip_lines; String *field_term=ex->field_term,*escaped=ex->escaped, *enclosed=ex->enclosed; bool is_fifo=0; + LOAD_FILE_INFO lf_info; + char * db = table_list->db ? table_list->db : thd->db; bool using_transactions; - DBUG_ENTER("mysql_load"); if (escaped->length() > 1 || enclosed->length() > 1) @@ -81,7 +95,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, MYF(0)); DBUG_RETURN(-1); } - if (!(table = open_ltable(thd,table_list,lock_type))) DBUG_RETURN(-1); if (!fields.elements) @@ -93,7 +106,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { // Part field list thd->dupp_field=0; - if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0)) + if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0)) DBUG_RETURN(-1); if (thd->dupp_field) { @@ -104,7 +117,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, uint tot_length=0; bool use_blobs=0,use_timestamp=0; - List_iterator<Item> it(fields); + List_iterator_fast<Item> it(fields); Item_field *field; while ((field=(Item_field*) it++)) @@ -163,8 +176,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (!my_stat(name,&stat_info,MYF(MY_WME))) DBUG_RETURN(-1); - // the file must be: - if (!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others + // if we are not in slave thread, the file must be: + if (!thd->slave_thread && + !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others #ifndef __EMX__ (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink #endif @@ -197,13 +211,27 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_RETURN(-1); // Can't allocate buffers } + if (!opt_old_rpl_compat && mysql_bin_log.is_open()) + { + lf_info.thd = thd; + lf_info.ex = ex; + lf_info.db = db; + lf_info.table_name = table_list->real_name; + lf_info.fields = &fields; + lf_info.handle_dup = handle_duplicates; + lf_info.wrote_create_file = 0; + lf_info.last_pos_in_file = HA_POS_ERROR; + read_info.set_io_cache_arg((void*)&lf_info); + } restore_record(table,2); thd->count_cuted_fields=1; /* calc cuted fields */ thd->cuted_fields=0L; if (ex->line_term->length() && field_term->length()) { - while (ex->skip_lines--) + // ex->skip_lines needs to be preserved for logging + uint skip_lines = ex->skip_lines; + while (skip_lines--) { if (read_info.next_line()) break; @@ -216,6 +244,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->time_stamp=0; table->next_number_field=table->found_next_number_field; VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); + VOID(table->file->extra(HA_EXTRA_BULK_INSERT_BEGIN)); if (handle_duplicates == DUP_IGNORE || handle_duplicates == DUP_REPLACE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); @@ -225,9 +254,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, error=read_fixed_length(thd,info,table,fields,read_info); else error=read_sep_field(thd,info,table,fields,read_info,*enclosed); - if (table->file->extra(HA_EXTRA_NO_CACHE) || - table->file->activate_all_index(thd)) - error=1; /* purecov: inspected */ + if (table->file->extra(HA_EXTRA_NO_CACHE)) + error=1; /* purecov: inspected */ + if (table->file->activate_all_index(thd)) + error=1; /* purecov: inspected */ table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->time_stamp=save_time_stamp; table->next_number_field=0; @@ -246,7 +276,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { if (using_transactions) ha_autocommit_or_rollback(thd,error); - DBUG_RETURN(-1); // Error on read + if (!opt_old_rpl_compat && mysql_bin_log.is_open()) + { + Delete_file_log_event d(thd); + mysql_bin_log.write(&d); + } + DBUG_RETURN(-1); // Error on read } sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted, info.records-info.copied,thd->cuted_fields); @@ -257,12 +292,20 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (!using_transactions) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; - if (!read_file_from_client && mysql_bin_log.is_open()) + if (mysql_bin_log.is_open()) { - ex->skip_lines = save_skip_lines; - Load_log_event qinfo(thd, ex, table->table_name, fields, + if (opt_old_rpl_compat && !read_file_from_client) + { + Load_log_event qinfo(thd, ex, db, table->table_name, fields, handle_duplicates); - mysql_bin_log.write(&qinfo); + mysql_bin_log.write(&qinfo); + } + if (!opt_old_rpl_compat) + { + read_info.end_io_cache(); // make sure last block gets logged + Execute_load_log_event e(thd); + mysql_bin_log.write(&e); + } } if (using_transactions) error=ha_autocommit_or_rollback(thd,error); @@ -278,7 +321,7 @@ static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, READ_INFO &read_info) { - List_iterator<Item> it(fields); + List_iterator_fast<Item> it(fields); Item_field *sql_field; DBUG_ENTER("read_fixed_length"); @@ -341,7 +384,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, List<Item> &fields, READ_INFO &read_info, String &enclosed) { - List_iterator<Item> it(fields); + List_iterator_fast<Item> it(fields); Item_field *sql_field; uint enclosed_length; DBUG_ENTER("read_sep_field"); @@ -489,6 +532,13 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term, my_free((gptr) buffer,MYF(0)); /* purecov: inspected */ error=1; } + else + { + need_end_io_cache = 1; + if (!opt_old_rpl_compat && mysql_bin_log.is_open()) + cache.pre_read = cache.pre_close = + (IO_CACHE_CALLBACK)log_loaded_block; + } } } @@ -497,7 +547,8 @@ READ_INFO::~READ_INFO() { if (!error) { - end_io_cache(&cache); + if (need_end_io_cache) + ::end_io_cache(&cache); my_free((gptr) buffer,MYF(0)); error=1; } @@ -807,3 +858,4 @@ bool READ_INFO::find_start_of_fields() } return 0; } + diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 18ab3c45359..a41ad1ba9ab 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -14,6 +14,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef EMBEDDED_LIBRARY +#define net_read_timeout net_read_timeout1 +#define net_write_timeout net_write_timeout1 +#endif #include "mysql_priv.h" #include "sql_acl.h" @@ -26,7 +30,6 @@ #define SCRAMBLE_LENGTH 8 - extern int yyparse(void); extern "C" pthread_mutex_t THR_LOCK_keycache; #ifdef SOLARIS @@ -43,6 +46,8 @@ static bool check_dup(THD *thd,const char *db,const char *name, static void mysql_init_query(THD *thd); static void remove_escape(char *name); static void refresh_status(void); +static bool append_file_to_dir(char **filename_ptr, char *table_name); +static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result); const char *any_db="*any*"; // Special symbol for check_access @@ -50,13 +55,13 @@ const char *command_name[]={ "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB", "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", - "Binlog Dump","Table Dump", "Connect Out" + "Binlog Dump","Table Dump", "Connect Out", "Register Slave" }; bool volatile abort_slave = 0; #ifdef HAVE_OPENSSL -extern VioSSLAcceptorFd* ssl_acceptor_fd; +extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ #ifdef __WIN__ @@ -118,18 +123,18 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, DBUG_PRINT("general", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_packet_length, - thd->host ? thd->host : thd->ip, thd->priv_user, + thd->host_or_ip, thd->priv_user, passwd[0] ? "yes": "no", thd->master_access, thd->db ? thd->db : "*none*")); if (thd->master_access & NO_ACCESS) { net_printf(net, ER_ACCESS_DENIED_ERROR, thd->user, - thd->host ? thd->host : thd->ip, + thd->host_or_ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), thd->user, - thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", + thd->host_or_ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); return(1); // Error already given } @@ -150,7 +155,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, (char*) "%s@%s on %s" : (char*) "%s@%s as anonymous on %s"), user, - thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip", + thd->host_or_ip, db ? db : (char*) ""); thd->db_access=0; if (max_user_connections && @@ -328,6 +333,7 @@ check_connections(THD *thd) return (ER_BAD_HOST_ERROR); if (!(thd->ip = my_strdup(ip,MYF(0)))) return (ER_OUT_OF_RESOURCES); + thd->host_or_ip=thd->ip; #if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) /* Fast local hostname resolve for Win32 */ if (!strcmp(thd->ip,"127.0.0.1")) @@ -350,6 +356,7 @@ check_connections(THD *thd) else /* Hostname given means that the connection was on a socket */ { DBUG_PRINT("general",("Host: %s",thd->host)); + thd->host_or_ip=thd->host; thd->ip=0; bzero((char*) &thd->remote,sizeof(struct sockaddr)); } @@ -426,9 +433,7 @@ check_connections(THD *thd) DBUG_PRINT("info", ("Agreed to change IO layer to SSL") ); /* Do the SSL layering. */ DBUG_PRINT("info", ("IO layer change in progress...")); - VioSocket* vio_socket = my_reinterpret_cast(VioSocket*)(net->vio); - VioSSL* vio_ssl = ssl_acceptor_fd->accept(vio_socket); - net->vio = my_reinterpret_cast(NetVio*) (vio_ssl); + sslaccept(ssl_acceptor_fd, net->vio); DBUG_PRINT("info", ("Reading user information over SSL layer")); if ((pkt_len=my_net_read(net)) == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE) @@ -530,7 +535,7 @@ pthread_handler_decl(handle_one_connection,arg) if ((error=check_connections(thd))) { // Wrong permissions if (error > 0) - net_printf(net,error,thd->host ? thd->host : thd->ip); + net_printf(net,error,thd->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) sleep(1); /* must wait after eof() */ @@ -561,7 +566,7 @@ pthread_handler_decl(handle_one_connection,arg) sql_print_error(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), thd->user ? thd->user : "unauthenticated", - (thd->host ? thd->host : thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); send_error(net,net->last_errno,NullS); @@ -664,7 +669,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) int error = 0; DBUG_ENTER("mysql_table_dump"); db = (db && db[0]) ? db : thd->db; - if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST)))) + if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST)))) DBUG_RETURN(1); // out of memory table_list->db = db; table_list->real_name = table_list->name = tbl_name; @@ -693,9 +698,8 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) goto err; } net_flush(&thd->net); - error = table->file->dump(thd,fd); - if(error) - my_error(ER_GET_ERRNO, MYF(0)); + if ((error = table->file->dump(thd,fd))) + my_error(ER_GET_ERRNO, MYF(0)); err: @@ -705,19 +709,14 @@ err: } - /* Execute one command from socket (query or simple command) */ bool do_command(THD *thd) { char *packet; uint old_timeout,packet_length; - bool error=0; NET *net; enum enum_server_command command; - // commands which will always take a long time should be marked with - // this so that they will not get logged to the slow query log - bool slow_command=FALSE; DBUG_ENTER("do_command"); net= &thd->net; @@ -744,7 +743,21 @@ bool do_command(THD *thd) vio_description(net->vio), command, command_name[command])); } - net->timeout=old_timeout; /* Timeout */ + net->timeout=old_timeout; // Timeout for writing + DBUG_RETURN(dispatch_command(command,thd, packet+1, packet_length)); +} + + +bool dispatch_command(enum enum_server_command command, THD *thd, + char* packet, uint packet_length) +{ + NET *net= &thd->net; + bool error=0; + // commands which will always take a long time should be marked with + // this so that they will not get logged to the slow query log + bool slow_command=FALSE; + DBUG_ENTER("dispatch_command"); + thd->command=command; VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id=query_id; @@ -753,23 +766,30 @@ bool do_command(THD *thd) thread_running++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->set_time(); - thd->lex.options=0; // We store status here - switch(command) { + thd->lex.select_lex.options=0; // We store status here + switch (command) { case COM_INIT_DB: - if (!mysql_change_db(thd,packet+1)) + if (!mysql_change_db(thd,packet)) mysql_log.write(thd,command,"%s",thd->db); break; + case COM_REGISTER_SLAVE: + { + if(register_slave(thd, (uchar*)packet, packet_length)) + send_error(&thd->net); + else + send_ok(&thd->net); + break; + } case COM_TABLE_DUMP: { slow_command = TRUE; - char* data = packet + 1; - uint db_len = *data; - uint tbl_len = *(data + db_len + 1); - char* db = sql_alloc(db_len + tbl_len + 2); - memcpy(db, data + 1, db_len); + uint db_len = *(uchar*)packet; + uint tbl_len = *(uchar*)(packet + db_len + 1); + char* db = thd->alloc(db_len + tbl_len + 2); + memcpy(db, packet + 1, db_len); char* tbl_name = db + db_len; *tbl_name++ = 0; - memcpy(tbl_name, data + db_len + 2, tbl_len); + memcpy(tbl_name, packet + db_len + 2, tbl_len); tbl_name[tbl_len] = 0; if(mysql_table_dump(thd, db, tbl_name, -1)) send_error(&thd->net); // dump to NET @@ -778,7 +798,7 @@ bool do_command(THD *thd) } case COM_CHANGE_USER: { - char *user= (char*) packet+1; + char *user= (char*) packet; char *passwd= strend(user)+1; char *db= strend(passwd)+1; @@ -814,16 +834,16 @@ bool do_command(THD *thd) case COM_QUERY: { - char *pos=packet+packet_length; // Point at end null + char *pos=packet-1+packet_length; // Point at end null /* Remove garage at end of query */ while (packet_length > 0 && pos[-1] == ';') { pos--; packet_length--; } - *pos=0; - if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),packet_length))) + if (!(thd->query= (char*) thd->memdup((gptr) (packet),packet_length+1))) break; + thd->query[packet_length]=0; thd->packet.shrink(net_buffer_length); // Reclaim some memory if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); @@ -850,8 +870,8 @@ bool do_command(THD *thd) break; } thd->free_list=0; - table_list.name=table_list.real_name=thd->strdup(packet+1); - thd->query=fields=thd->strdup(strend(packet+1)+1); + table_list.name=table_list.real_name=thd->strdup(packet); + thd->query=fields=thd->strdup(strend(packet)+1); mysql_log.write(thd,command,"%s %s",table_list.real_name,fields); remove_escape(table_list.real_name); // This can't have wildcards @@ -871,9 +891,9 @@ bool do_command(THD *thd) error=TRUE; // End server break; - case COM_CREATE_DB: + case COM_CREATE_DB: // QQ: To be removed { - char *db=thd->strdup(packet+1); + char *db=thd->strdup(packet); // null test to handle EOM if (!db || !stripp_sp(db) || check_db_name(db)) { @@ -882,21 +902,24 @@ bool do_command(THD *thd) } if (check_access(thd,CREATE_ACL,db,0,1)) break; - mysql_log.write(thd,command,packet+1); + mysql_log.write(thd,command,packet); mysql_create_db(thd,db,0); break; } - case COM_DROP_DB: + case COM_DROP_DB: // QQ: To be removed { - char *db=thd->strdup(packet+1); + char *db=thd->strdup(packet); // null test to handle EOM if (!db || !stripp_sp(db) || check_db_name(db)) { net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); break; } - if (check_access(thd,DROP_ACL,db,0,1) || end_active_trans(thd)) + if (thd->locked_tables || thd->active_transaction()) + { + send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); break; + } mysql_log.write(thd,command,db); mysql_rm_db(thd,db,0); break; @@ -911,13 +934,13 @@ bool do_command(THD *thd) ulong pos; ushort flags; uint32 slave_server_id; - pos = uint4korr(packet + 1); - flags = uint2korr(packet + 5); + pos = uint4korr(packet); + flags = uint2korr(packet + 4); pthread_mutex_lock(&LOCK_server_id); - kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7)); + kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6)); thd->server_id = slave_server_id; pthread_mutex_unlock(&LOCK_server_id); - mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags); + mysql_binlog_send(thd, thd->strdup(packet + 10), pos, flags); // fake COM_QUIT -- if we get here, the thread needs to terminate error = TRUE; net->error = 0; @@ -925,7 +948,7 @@ bool do_command(THD *thd) } case COM_REFRESH: { - uint options=(uchar) packet[1]; + uint options=(uchar) packet[0]; if (check_access(thd,RELOAD_ACL,any_db)) break; mysql_log.write(thd,command,NullS); @@ -960,7 +983,7 @@ bool do_command(THD *thd) char buff[200]; ulong uptime = (ulong) (thd->start_time - start_time); sprintf((char*) buff, - "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %d Queries per second avg: %.3f", + "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f", uptime, (int) thread_count,thd->query_id,long_query_count, opened_tables,refresh_version, cached_tables(), @@ -986,7 +1009,7 @@ bool do_command(THD *thd) break; case COM_PROCESS_KILL: { - ulong id=(ulong) uint4korr(packet+1); + ulong id=(ulong) uint4korr(packet); kill_one_thread(thd,id); break; } @@ -1023,7 +1046,7 @@ bool do_command(THD *thd) thd->proc_info="logging slow query"; if ((ulong) (thd->start_time - thd->time_after_lock) > long_query_time || - ((thd->lex.options & + ((thd->lex.select_lex.options & (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) && (specialflag & SPECIAL_LONG_LOG_FORMAT))) { @@ -1054,19 +1077,24 @@ mysql_execute_command(void) int res=0; THD *thd=current_thd; LEX *lex= &thd->lex; - TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first; + TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first; + SELECT_LEX *select_lex = lex->select; DBUG_ENTER("mysql_execute_command"); - if(table_rules_on && thd->slave_thread && tables && !tables_ok(thd,tables)) - DBUG_VOID_RETURN; // skip if we are in the slave thread, some table - // rules have been given and the table list says the query should not be - // replicated - + /* + Skip if we are in the slave thread, some table rules have been given + and the table list says the query should not be replicated + */ + if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) || + (table_rules_on && tables && thd->slave_thread && + !tables_ok(thd,tables))) + DBUG_VOID_RETURN; + switch (lex->sql_command) { case SQLCOM_SELECT: { select_result *result; - if (lex->options & SELECT_DESCRIBE) + if (select_lex->options & SELECT_DESCRIBE) lex->exchange=0; if (tables) { @@ -1084,10 +1112,12 @@ mysql_execute_command(void) break; // Error message is given } - thd->offset_limit=lex->offset_limit; - thd->select_limit=lex->select_limit+lex->offset_limit; - if (thd->select_limit < lex->select_limit) + thd->offset_limit=select_lex->offset_limit; + thd->select_limit=select_lex->select_limit+select_lex->offset_limit; + if (thd->select_limit < select_lex->select_limit) thd->select_limit= HA_POS_ERROR; // no limit + if (thd->select_limit == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; if (lex->exchange) { @@ -1112,8 +1142,8 @@ mysql_execute_command(void) { res= -1; #ifdef DELETE_ITEMS - delete lex->having; - delete lex->where; + delete select_lex->having; + delete select_lex->where; #endif break; } @@ -1130,73 +1160,86 @@ mysql_execute_command(void) } if (!(res=open_and_lock_tables(thd,tables))) - { - res=mysql_select(thd,tables,lex->item_list, - lex->where, - lex->ftfunc_list, - (ORDER*) lex->order_list.first, - (ORDER*) lex->group_list.first, - lex->having, - (ORDER*) lex->proc_list.first, - lex->options | thd->options, - result); - if (res) - result->abort(); - } - delete result; -#ifdef DELETE_ITEMS - delete lex->having; - delete lex->where; -#endif + res=handle_select(thd, lex, result); + else + delete result; break; } case SQLCOM_PURGE: - { - if (check_process_priv(thd)) - goto error; - res = purge_master_logs(thd, lex->to_log); - break; - } + { + if (check_process_priv(thd)) + goto error; + res = purge_master_logs(thd, lex->to_log); + break; + } + case SQLCOM_SHOW_NEW_MASTER: + { + if(check_access(thd, FILE_ACL, any_db)) + goto error; + res = show_new_master(thd); + break; + } + case SQLCOM_SHOW_SLAVE_HOSTS: + { + if(check_access(thd, FILE_ACL, any_db)) + goto error; + res = show_slave_hosts(thd); + break; + } + case SQLCOM_SHOW_BINLOG_EVENTS: + { + if(check_access(thd, FILE_ACL, any_db)) + goto error; + res = show_binlog_events(thd); + break; + } case SQLCOM_BACKUP_TABLE: - { - if (check_db_used(thd,tables) || - check_table_access(thd,SELECT_ACL, tables) || - check_access(thd, FILE_ACL, any_db)) - goto error; /* purecov: inspected */ - res = mysql_backup_table(thd, tables); + { + if (check_db_used(thd,tables) || + check_table_access(thd,SELECT_ACL, tables) || + check_access(thd, FILE_ACL, any_db)) + goto error; /* purecov: inspected */ + res = mysql_backup_table(thd, tables); - break; - } + break; + } case SQLCOM_RESTORE_TABLE: - { - if (check_db_used(thd,tables) || - check_table_access(thd,INSERT_ACL, tables) || - check_access(thd, FILE_ACL, any_db)) - goto error; /* purecov: inspected */ - res = mysql_restore_table(thd, tables); - break; - } + { + if (check_db_used(thd,tables) || + check_table_access(thd,INSERT_ACL, tables) || + check_access(thd, FILE_ACL, any_db)) + goto error; /* purecov: inspected */ + res = mysql_restore_table(thd, tables); + break; + } case SQLCOM_CHANGE_MASTER: - { - if(check_access(thd, PROCESS_ACL, any_db)) - goto error; - res = change_master(thd); - break; - } + { + if(check_access(thd, PROCESS_ACL, any_db)) + goto error; + res = change_master(thd); + break; + } case SQLCOM_SHOW_SLAVE_STAT: - { - if (check_process_priv(thd)) - goto error; - res = show_master_info(thd); - break; - } + { + if (check_process_priv(thd)) + goto error; + res = show_master_info(thd); + break; + } case SQLCOM_SHOW_MASTER_STAT: - { - if (check_process_priv(thd)) - goto error; - res = show_binlog_info(thd); - break; - } + { + if (check_process_priv(thd)) + goto error; + res = show_binlog_info(thd); + break; + } + + case SQLCOM_LOAD_MASTER_DATA: // sync with master + if(check_process_priv(thd)) + goto error; + res = load_master_data(thd); + break; + case SQLCOM_LOAD_MASTER_TABLE: if (!tables->db) @@ -1211,7 +1254,7 @@ mysql_execute_command(void) bool error=check_grant(thd,CREATE_ACL,tables); tables->next=tmp_table_list; if (error) - goto error; + goto error; } if (strlen(tables->name) > NAME_LEN) { @@ -1219,9 +1262,7 @@ mysql_execute_command(void) break; } - thd->last_nx_table = tables->real_name; - thd->last_nx_db = tables->db; - if (fetch_nx_table(thd, &glob_mi)) + if (fetch_nx_table(thd, tables->db, tables->real_name, &glob_mi, 0)) break; // fetch_nx_table did send the error to the client send_ok(&thd->net); break; @@ -1250,7 +1291,14 @@ mysql_execute_command(void) res=0; break; } - if (lex->item_list.elements) // With select + /* Fix names if symlinked tables */ + if (append_file_to_dir(&lex->create_info.data_file_name, tables->name) || + append_file_to_dir(&lex->create_info.index_file_name, tables->name)) + { + res=-1; + break; + } + if (select_lex->item_list.elements) // With select { select_result *result; @@ -1268,32 +1316,22 @@ mysql_execute_command(void) for (table = tables->next ; table ; table=table->next) table->lock_type= lex->lock_option; } - thd->offset_limit=lex->offset_limit; - thd->select_limit=lex->select_limit+lex->offset_limit; - if (thd->select_limit < lex->select_limit) + thd->offset_limit=select_lex->offset_limit; + thd->select_limit=select_lex->select_limit+select_lex->offset_limit; + if (thd->select_limit < select_lex->select_limit) thd->select_limit= HA_POS_ERROR; // No limit + /* Skip first table, which is the table we are creating */ + lex->select_lex.table_list.first= + (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next); if (!(res=open_and_lock_tables(thd,tables->next))) { - if ((result=new select_create(tables->db ? tables->db : thd->db, - tables->real_name, &lex->create_info, - lex->create_list, - lex->key_list, - lex->item_list,lex->duplicates))) - { - res=mysql_select(thd,tables->next,lex->item_list, - lex->where, - lex->ftfunc_list, - (ORDER*) lex->order_list.first, - (ORDER*) lex->group_list.first, - lex->having, - (ORDER*) lex->proc_list.first, - lex->options | thd->options, - result); - if (res) - result->abort(); - delete result; - } + if ((result=new select_create(tables->db ? tables->db : thd->db, + tables->real_name, &lex->create_info, + lex->create_list, + lex->key_list, + select_lex->item_list,lex->duplicates))) + res=handle_select(thd, lex, result); else res= -1; } @@ -1343,10 +1381,10 @@ mysql_execute_command(void) } if (!tables->db) tables->db=thd->db; - if (!lex->db) - lex->db=tables->db; + if (!select_lex->db) + select_lex->db=tables->db; if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) || - check_access(thd,INSERT_ACL | CREATE_ACL,lex->db,&priv) || + check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) || check_merge_table_access(thd, tables->db, (TABLE_LIST *) lex->create_info.merge_list.first)) @@ -1362,22 +1400,25 @@ mysql_execute_command(void) TABLE_LIST tmp_table; bzero((char*) &tmp_table,sizeof(tmp_table)); tmp_table.real_name=lex->name; - tmp_table.db=lex->db; + tmp_table.db=select_lex->db; tmp_table.grant.privilege=priv; if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables)) goto error; } } + /* Don't yet allow changing of symlinks with ALTER TABLE */ + lex->create_info.data_file_name=lex->create_info.index_file_name=0; /* ALTER TABLE ends previous transaction */ if (end_active_trans(thd)) res= -1; else - res= mysql_alter_table(thd, lex->db, lex->name, + res= mysql_alter_table(thd, select_lex->db, lex->name, &lex->create_info, tables, lex->create_list, lex->key_list, lex->drop_list, lex->alter_list, - (ORDER *) lex->order_list.first, - lex->drop_primary, lex->duplicates); + (ORDER *) select_lex->order_list.first, + lex->drop_primary, lex->duplicates, + lex->alter_keys_onoff, lex->simple_alter); break; } #endif @@ -1401,7 +1442,7 @@ mysql_execute_command(void) old_list.next=new_list.next=0; if (check_grant(thd,ALTER_ACL,&old_list) || (!test_all_bits(table->next->grant.privilege, - INSERT_ACL | CREATE_ACL) && + INSERT_ACL | CREATE_ACL) && check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list))) goto error; } @@ -1439,21 +1480,21 @@ mysql_execute_command(void) } #endif case SQLCOM_REPAIR: - { - if (check_db_used(thd,tables) || - check_table_access(thd,SELECT_ACL | INSERT_ACL, tables)) - goto error; /* purecov: inspected */ - res = mysql_repair_table(thd, tables, &lex->check_opt); - break; - } + { + if (check_db_used(thd,tables) || + check_table_access(thd,SELECT_ACL | INSERT_ACL, tables)) + goto error; /* purecov: inspected */ + res = mysql_repair_table(thd, tables, &lex->check_opt); + break; + } case SQLCOM_CHECK: - { - if (check_db_used(thd,tables) || - check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables)) - goto error; /* purecov: inspected */ - res = mysql_check_table(thd, tables, &lex->check_opt); - break; - } + { + if (check_db_used(thd,tables) || + check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables)) + goto error; /* purecov: inspected */ + res = mysql_check_table(thd, tables, &lex->check_opt); + break; + } case SQLCOM_ANALYZE: { if (check_db_used(thd,tables) || @@ -1495,21 +1536,22 @@ mysql_execute_command(void) goto error; if (grant_option && check_grant(thd,UPDATE_ACL,tables)) goto error; - if (lex->item_list.elements != lex->value_list.elements) + if (select_lex->item_list.elements != lex->value_list.elements) { send_error(&thd->net,ER_WRONG_VALUE_COUNT); DBUG_VOID_RETURN; } res = mysql_update(thd,tables, - lex->item_list, + select_lex->item_list, lex->value_list, - lex->where, - lex->select_limit, + select_lex->where, + (ORDER *) select_lex->order_list.first, + select_lex->select_limit, lex->duplicates, lex->lock_option); #ifdef DELETE_ITEMS - delete lex->where; + delete select_lex->where; #endif break; case SQLCOM_INSERT: @@ -1536,6 +1578,7 @@ mysql_execute_command(void) case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { + // Check that we have modify privileges for the first table and // select privileges for the rest { @@ -1553,9 +1596,9 @@ mysql_execute_command(void) } select_result *result; - thd->offset_limit=lex->offset_limit; - thd->select_limit=lex->select_limit+lex->offset_limit; - if (thd->select_limit < lex->select_limit) + thd->offset_limit=select_lex->offset_limit; + thd->select_limit=select_lex->select_limit+select_lex->offset_limit; + if (thd->select_limit < select_lex->select_limit) thd->select_limit= HA_POS_ERROR; // No limit if (check_dup(thd,tables->db,tables->real_name,tables->next)) @@ -1563,42 +1606,41 @@ mysql_execute_command(void) net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } - tables->lock_type=TL_WRITE; // update first table + tables->lock_type=TL_WRITE; // update first table { TABLE_LIST *table; for (table = tables->next ; table ; table=table->next) table->lock_type= lex->lock_option; } - if (!(res=open_and_lock_tables(thd,tables))) + + /* Skip first table, which is the table we are inserting in */ + lex->select_lex.table_list.first= + (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next); + if (!(res=open_and_lock_tables(thd, tables))) { if ((result=new select_insert(tables->table,&lex->field_list, lex->sql_command == SQLCOM_REPLACE_SELECT ? DUP_REPLACE : DUP_IGNORE))) - { - res=mysql_select(thd,tables->next,lex->item_list, - lex->where, - lex->ftfunc_list, - (ORDER*) lex->order_list.first, - (ORDER*) lex->group_list.first, - lex->having, - (ORDER*) lex->proc_list.first, - lex->options | thd->options, - result); - delete result; - } - else - res= -1; + res=handle_select(thd,lex,result); } -#ifdef DELETE_ITEMS - delete lex->having; - delete lex->where; -#endif + else + res= -1; break; } case SQLCOM_TRUNCATE: - lex->where=0; - lex->select_limit=HA_POS_ERROR; - /* Fall through */ + if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege)) + goto error; /* purecov: inspected */ + /* + Don't allow this within a transaction because we want to use + re-generate table + */ + if (thd->locked_tables || thd->active_transaction()) + { + send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS); + goto error; + } + res=mysql_truncate(thd,tables); + break; case SQLCOM_DELETE: { if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege)) @@ -1611,20 +1653,87 @@ mysql_execute_command(void) if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd)) res= -1; else - res = mysql_delete(thd,tables,lex->where,lex->select_limit, - lex->lock_option, lex->options); + res = mysql_delete(thd,tables, select_lex->where, + (ORDER*) select_lex->order_list.first, + select_lex->select_limit, lex->lock_option, + select_lex->options); break; } - case SQLCOM_DROP_TABLE: + case SQLCOM_MULTI_DELETE: + { + TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first; + TABLE_LIST *auxi; + uint table_count=0; + multi_delete *result; + + /* sql_yacc guarantees that tables and aux_tables are not zero */ + if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || + check_table_access(thd,SELECT_ACL, tables) || + check_table_access(thd,DELETE_ACL, aux_tables)) + goto error; + if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) + { + send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + goto error; + } + for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) { - if (check_table_access(thd,DROP_ACL,tables)) - goto error; /* purecov: inspected */ - if (end_active_trans(thd)) - res= -1; - else - res = mysql_rm_table(thd,tables,lex->drop_if_exists); + table_count++; + /* All tables in aux_tables must be found in FROM PART */ + TABLE_LIST *walk; + for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next) + { + if (!strcmp(auxi->real_name,walk->real_name) && + !strcmp(walk->db,auxi->db)) + break; + } + if (!walk) + { + net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name); + goto error; + } + auxi->lock_type=walk->lock_type=TL_WRITE; + auxi->table= (TABLE *) walk; // Remember corresponding table + } + tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); + if (add_item_to_list(new Item_null())) + { + res= -1; + break; } + thd->proc_info="init"; + if ((res=open_and_lock_tables(thd,tables))) + break; + /* Fix tables-to-be-deleted-from list to point at opened tables */ + for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) + auxi->table= ((TABLE_LIST*) auxi->table)->table; + if ((result=new multi_delete(thd,aux_tables,lex->lock_option, + table_count)) && ! thd->fatal_error) + { + res=mysql_select(thd,tables,select_lex->item_list, + select_lex->where,select_lex->ftfunc_list, + (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, + (ORDER *)NULL, + select_lex->options | thd->options | + SELECT_NO_JOIN_CACHE, + result); + } + else + res= -1; // Error is not sent + delete result; + close_thread_tables(thd); break; + } + case SQLCOM_DROP_TABLE: + { + if (check_table_access(thd,DROP_ACL,tables)) + goto error; /* purecov: inspected */ + if (end_active_trans(thd)) + res= -1; + else + res = mysql_rm_table(thd,tables,lex->drop_if_exists); + } + break; case SQLCOM_DROP_INDEX: if (!tables->db) tables->db=thd->db; @@ -1639,7 +1748,7 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_DATABASES: #if defined(DONT_ALLOW_SHOW_COMMANDS) - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else if ((specialflag & SPECIAL_SKIP_SHOW_DB) && @@ -1675,13 +1784,12 @@ mysql_execute_command(void) #endif case SQLCOM_SHOW_TABLES: /* FALL THROUGH */ - case SQLCOM_SHOW_OPEN_TABLES: #ifdef DONT_ALLOW_SHOW_COMMANDS send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { - char *db=lex->db ? lex->db : thd->db; + char *db=select_lex->db ? select_lex->db : thd->db; if (!db) { send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ @@ -1696,34 +1804,32 @@ mysql_execute_command(void) if (check_access(thd,SELECT_ACL,db,&thd->col_access)) goto error; /* purecov: inspected */ /* grant is checked in mysqld_show_tables */ - if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES) - res= mysqld_show_open_tables(thd,db, - (lex->wild ? lex->wild->ptr() : NullS)); - else if (lex->options & SELECT_DESCRIBE) + if (select_lex->options & SELECT_DESCRIBE) res= mysqld_extend_show_tables(thd,db, - (lex->wild ? lex->wild->ptr() : NullS)); + (lex->wild ? lex->wild->ptr() : NullS)); else res= mysqld_show_tables(thd,db, (lex->wild ? lex->wild->ptr() : NullS)); break; } #endif + case SQLCOM_SHOW_OPEN_TABLES: + res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS)); + break; case SQLCOM_SHOW_FIELDS: #ifdef DONT_ALLOW_SHOW_COMMANDS send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { - char *db=tables->db ? tables->db : thd->db; - if (!db) + char *db=tables->db; + if (!*db) { send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' remove_escape(tables->name); - if (!tables->db) - tables->db=thd->db; if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access)) goto error; /* purecov: inspected */ tables->grant.privilege=thd->col_access; @@ -1741,7 +1847,7 @@ mysql_execute_command(void) DBUG_VOID_RETURN; #else { - char *db=tables->db ? tables->db : thd->db; + char *db=tables->db; if (!db) { send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ @@ -1761,7 +1867,7 @@ mysql_execute_command(void) } #endif case SQLCOM_CHANGE_DB: - mysql_change_db(thd,lex->db); + mysql_change_db(thd,select_lex->db); break; case SQLCOM_LOAD: { @@ -1775,7 +1881,7 @@ mysql_execute_command(void) else { if (check_access(thd,privilege,tables->db,&tables->grant.privilege) || - grant_option && check_grant(thd,privilege,tables)) + grant_option && check_grant(thd,privilege,tables)) goto error; } res=mysql_load(thd, lex->exchange, tables, lex->field_list, @@ -1785,10 +1891,10 @@ mysql_execute_command(void) case SQLCOM_SET_OPTION: { uint org_options=thd->options; - thd->options=lex->options; + thd->options=select_lex->options; thd->update_lock_default= ((thd->options & OPTION_LOW_PRIORITY_UPDATES) ? TL_WRITE_LOW_PRIORITY : TL_WRITE); - thd->default_select_limit=lex->select_limit; + thd->default_select_limit=select_lex->select_limit; thd->tx_isolation=lex->tx_isolation; if (thd->gemini_spin_retries != lex->gemini_spin_retries) { @@ -1799,7 +1905,7 @@ mysql_execute_command(void) thd->options,(long) thd->default_select_limit)); /* Check if auto_commit mode changed */ - if ((org_options ^ lex->options) & OPTION_NOT_AUTO_COMMIT) + if ((org_options ^ select_lex->options) & OPTION_NOT_AUTO_COMMIT) { if ((org_options & OPTION_NOT_AUTO_COMMIT)) { @@ -1833,13 +1939,7 @@ mysql_execute_command(void) thd->options&= ~(ulong) (OPTION_TABLE_LOCK); } if (thd->global_read_lock) - { - thd->global_read_lock=0; - pthread_mutex_lock(&LOCK_open); - global_read_lock--; - pthread_cond_broadcast(&COND_refresh); - pthread_mutex_unlock(&LOCK_open); - } + unlock_global_read_lock(thd); send_ok(&thd->net); break; case SQLCOM_LOCK_TABLES: @@ -1851,6 +1951,8 @@ mysql_execute_command(void) } if (check_db_used(thd,tables) || end_active_trans(thd)) goto error; + if (grant_option && check_grant(thd,SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL,tables)) + goto error; thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; if (!(res=open_and_lock_tables(thd,tables))) @@ -1864,30 +1966,34 @@ mysql_execute_command(void) thd->in_lock_tables=0; break; case SQLCOM_CREATE_DB: + { + if (!stripp_sp(lex->name) || check_db_name(lex->name)) { - if (!stripp_sp(lex->name) || check_db_name(lex->name)) - { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); - break; - } - if (check_access(thd,CREATE_ACL,lex->name,0,1)) - break; - mysql_create_db(thd,lex->name,lex->create_info.options); + net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); break; } + if (check_access(thd,CREATE_ACL,lex->name,0,1)) + break; + res=mysql_create_db(thd,lex->name,lex->create_info.options); + break; + } case SQLCOM_DROP_DB: + { + if (!stripp_sp(lex->name) || check_db_name(lex->name)) { - if (!stripp_sp(lex->name) || check_db_name(lex->name)) - { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); - break; - } - if (check_access(thd,DROP_ACL,lex->name,0,1) || - end_active_trans(thd)) - break; - mysql_rm_db(thd,lex->name,lex->drop_if_exists); + net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + break; + } + if (check_access(thd,DROP_ACL,lex->name,0,1)) break; + if (thd->locked_tables || thd->active_transaction()) + { + send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + goto error; } + res=mysql_rm_db(thd,lex->name,lex->drop_if_exists); + break; + } case SQLCOM_CREATE_FUNCTION: if (check_access(thd,INSERT_ACL,"mysql",0,1)) break; @@ -1908,78 +2014,78 @@ mysql_execute_command(void) res= -1; #endif break; - case SQLCOM_REVOKE: - case SQLCOM_GRANT: - { - if (tables && !tables->db) - tables->db=thd->db; - if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, - tables && tables->db ? tables->db : lex->db, - tables ? &tables->grant.privilege : 0, - tables ? 0 : 1)) - goto error; - - /* Check that the user isn't trying to change a password for another - user if he doesn't have UPDATE privilege to the MySQL database */ - - if (thd->user) // If not replication - { - LEX_USER *user; - List_iterator <LEX_USER> user_list(lex->users_list); - while ((user=user_list++)) - { - if (user->password.str && - (strcmp(thd->user,user->user.str) || - user->host.str && - my_strcasecmp(user->host.str, thd->host ? thd->host : thd->ip))) - { - if (check_access(thd, UPDATE_ACL, "mysql",0,1)) - goto error; - break; // We are allowed to do changes - } - } - } - if (tables) - { - if (grant_option && check_grant(thd, - (lex->grant | lex->grant_tot_col | - GRANT_ACL), - tables)) - goto error; - res = mysql_table_grant(thd,tables,lex->users_list, lex->columns, - lex->grant, lex->sql_command == SQLCOM_REVOKE); - if(!res) - { - mysql_update_log.write(thd, thd->query,thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query); - mysql_bin_log.write(&qinfo); - } - } - } - else - { - if (lex->columns.elements) - { - net_printf(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); - res=1; - } - else - res = mysql_grant(thd, lex->db, lex->users_list, lex->grant, - lex->sql_command == SQLCOM_REVOKE); - if (!res) - { - mysql_update_log.write(thd, thd->query,thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query); - mysql_bin_log.write(&qinfo); - } - } - } - break; - } + case SQLCOM_REVOKE: + case SQLCOM_GRANT: + { + if (tables && !tables->db) + tables->db=thd->db; + if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, + tables && tables->db ? tables->db : select_lex->db, + tables ? &tables->grant.privilege : 0, + tables ? 0 : 1)) + goto error; + + /* Check that the user isn't trying to change a password for another + user if he doesn't have UPDATE privilege to the MySQL database */ + + if (thd->user) // If not replication + { + LEX_USER *user; + List_iterator <LEX_USER> user_list(lex->users_list); + while ((user=user_list++)) + { + if (user->password.str && + (strcmp(thd->user,user->user.str) || + user->host.str && + my_strcasecmp(user->host.str, thd->host_or_ip))) + { + if (check_access(thd, UPDATE_ACL, "mysql",0,1)) + goto error; + break; // We are allowed to do changes + } + } + } + if (tables) + { + if (grant_option && check_grant(thd, + (lex->grant | lex->grant_tot_col | + GRANT_ACL), + tables)) + goto error; + res = mysql_table_grant(thd,tables,lex->users_list, lex->columns, + lex->grant, lex->sql_command == SQLCOM_REVOKE); + if(!res) + { + mysql_update_log.write(thd, thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query); + mysql_bin_log.write(&qinfo); + } + } + } + else + { + if (lex->columns.elements) + { + send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + res=1; + } + else + res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, + lex->sql_command == SQLCOM_REVOKE); + if (!res) + { + mysql_update_log.write(thd, thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query); + mysql_bin_log.write(&qinfo); + } + } + } + break; + } case SQLCOM_FLUSH: case SQLCOM_RESET: if (check_access(thd,RELOAD_ACL,any_db) || check_db_used(thd, tables)) @@ -1994,13 +2100,40 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_GRANTS: res=0; - if ((thd->priv_user && !strcmp(thd->priv_user,lex->grant_user->user.str)) || + if ((thd->priv_user && + !strcmp(thd->priv_user,lex->grant_user->user.str)) || !check_access(thd, SELECT_ACL, "mysql",0,1)) { res = mysql_show_grants(thd,lex->grant_user); } break; + case SQLCOM_HA_OPEN: + if (check_db_used(thd,tables) || + check_table_access(thd,SELECT_ACL, tables)) + goto error; + res = mysql_ha_open(thd, tables); + break; + case SQLCOM_HA_CLOSE: + if (check_db_used(thd,tables)) + goto error; + res = mysql_ha_close(thd, tables); + break; + case SQLCOM_HA_READ: + if (check_db_used(thd,tables) || + check_table_access(thd,SELECT_ACL, tables)) + goto error; + res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir, + lex->insert_list, lex->ha_rkey_mode, select_lex->where, + select_lex->select_limit, select_lex->offset_limit); + break; + case SQLCOM_BEGIN: + if (thd->locked_tables) + { + thd->lock=thd->locked_tables; + thd->locked_tables=0; // Will be automaticly closed + close_thread_tables(thd); // Free tables + } if (end_active_trans(thd)) { res= -1; @@ -2072,7 +2205,7 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, else save_priv= &dummy; - if (!db && !thd->db && !dont_check_global_grants) + if (!db[0] && !thd->db && !dont_check_global_grants) { send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ return TRUE; /* purecov: tested */ @@ -2088,7 +2221,7 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, { // We can never grant this net_printf(&thd->net,ER_ACCESS_DENIED_ERROR, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ return TRUE; /* purecov: tested */ } @@ -2111,7 +2244,7 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv, return FALSE; /* Ok */ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"), + thd->host_or_ip, db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ return TRUE; /* purecov: tested */ } @@ -2154,10 +2287,8 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables) return TRUE; // Access denied } if (grant_option) - { - want_access &= ~EXTRA_ACL; // Remove SHOW attribute - return check_grant(thd,want_access,org_tables); - } + return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, + test(want_access & EXTRA_ACL)); return FALSE; } @@ -2268,13 +2399,14 @@ static void mysql_init_query(THD *thd) { DBUG_ENTER("mysql_init_query"); - thd->lex.item_list.empty(); + thd->lex.select_lex.item_list.empty(); thd->lex.value_list.empty(); - thd->lex.table_list.elements=0; - thd->free_list=0; - - thd->lex.table_list.first=0; - thd->lex.table_list.next= (byte**) &thd->lex.table_list.first; + thd->lex.select_lex.table_list.elements=0; + thd->free_list=0; thd->lex.union_option=0; + thd->lex.select = &thd->lex.select_lex; + thd->lex.select_lex.table_list.first=0; + thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first; + thd->lex.select_lex.next=0; thd->fatal_error=0; // Safety thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; thd->sent_row_count=thd->examined_row_count=0; @@ -2284,19 +2416,32 @@ mysql_init_query(THD *thd) void mysql_init_select(LEX *lex) { - lex->where=lex->having=0; - lex->select_limit=current_thd->default_select_limit; - lex->offset_limit=0L; - lex->options=0; + SELECT_LEX *select_lex = lex->select; + select_lex->where=select_lex->having=0; + select_lex->select_limit=current_thd->default_select_limit; + select_lex->offset_limit=0; + select_lex->options=0; select_lex->linkage=UNSPECIFIED_TYPE; lex->exchange = 0; lex->proc_list.first=0; - lex->order_list.elements=lex->group_list.elements=0; - lex->order_list.first=0; - lex->order_list.next= (byte**) &lex->order_list.first; - lex->group_list.first=0; - lex->group_list.next= (byte**) &lex->group_list.first; + select_lex->order_list.elements=select_lex->group_list.elements=0; + select_lex->order_list.first=0; + select_lex->order_list.next= (byte**) &select_lex->order_list.first; + select_lex->group_list.first=0; + select_lex->group_list.next= (byte**) &select_lex->group_list.first; + select_lex->next = (SELECT_LEX *)NULL; } +void +mysql_new_select(LEX *lex) +{ + SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX)); + lex->select->next=select_lex; + lex->select=select_lex; + select_lex->table_list.next= (byte**) &select_lex->table_list.first; + select_lex->item_list.empty(); select_lex->when_list.empty(); + select_lex->expr_list.empty(); select_lex->interval_list.empty(); + select_lex->use_index.empty(); select_lex->ftfunc_list.empty(); +} void mysql_parse(THD *thd,char *inBuf,uint length) @@ -2616,6 +2761,8 @@ add_proc_to_list(Item *item) static void remove_escape(char *name) { + if (!*name) // For empty DB names + return; char *to; #ifdef USE_MB char *strend=name+(uint) strlen(name); @@ -2674,7 +2821,6 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, register TABLE_LIST *ptr; THD *thd=current_thd; char *alias_str; - const char *current_db; DBUG_ENTER("add_table_to_list"); if (!table) @@ -2689,13 +2835,13 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, } if (!alias) /* Alias is case sensitive */ - if (!(alias_str=sql_strmake(alias_str,table->table.length))) + if (!(alias_str=thd->memdup(alias_str,table->table.length+1))) DBUG_RETURN(0); if (lower_case_table_names) casedn_str(table->table.str); if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) DBUG_RETURN(0); /* purecov: inspected */ - ptr->db= table->db.str; + ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) ""); ptr->real_name=table->table.str; ptr->name=alias_str; ptr->lock_type=flags; @@ -2708,26 +2854,83 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, sizeof(*ignore_index)); /* check that used name is unique */ - current_db=thd->db ? thd->db : ""; - if (flags != TL_IGNORE) { - for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.table_list.first ; tables ; + for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ; tables ; tables=tables->next) { - if (!strcmp(alias_str,tables->name) && - !strcmp(ptr->db ? ptr->db : current_db, - tables->db ? tables->db : current_db)) + if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db)) { net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ } } } - link_in_list(&thd->lex.table_list,(byte*) ptr,(byte**) &ptr->next); + link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next); DBUG_RETURN(ptr); } + +/* +** This is used for UNION to create a new table list of all used tables +** The table_list->table entry in all used tables are set to point +** to the entries in this list. +*/ + +static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result) +{ + /* Handle the case when we are not using union */ + if (!lex->select_lex.next) + { + *result= (TABLE_LIST*) lex->select_lex.table_list.first; + return 0; + } + + SELECT_LEX *sl; + TABLE_LIST **new_table_list= result, *aux; + + *new_table_list=0; // end result list + for (sl= &lex->select_lex; sl; sl=sl->next) + { + if (sl->order_list.first && sl->next) + { + net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY"); + return 1; + } + if ((aux= (TABLE_LIST*) sl->table_list.first)) + { + TABLE_LIST *next; + for (; aux; aux=next) + { + TABLE_LIST *cursor; + next= aux->next; + for (cursor= *result; cursor; cursor=cursor->next) + if (!strcmp(cursor->db,aux->db) && + !strcmp(cursor->real_name,aux->real_name) && + !strcmp(cursor->name, aux->name)) + break; + if (!cursor) + { + /* Add not used table to the total table list */ + aux->lock_type= lex->lock_option; + if (!(cursor = (TABLE_LIST *) thd->memdup((byte*) aux, + sizeof(*aux)))) + { + send_error(&thd->net,0); + return 1; + } + *new_table_list= cursor; + new_table_list= &cursor->next; + *new_table_list=0; // end result list + } + aux->table=(TABLE *) cursor; + } + } + } + return 0; +} + + void add_join_on(TABLE_LIST *b,Item *expr) { if (!b->on_expr) @@ -2750,10 +2953,8 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) static bool check_dup(THD *thd,const char *db,const char *name, TABLE_LIST *tables) { - const char *thd_db=thd->db ? thd->db : any_db; for (; tables ; tables=tables->next) - if (!strcmp(name,tables->real_name) && - !strcmp(db ? db : thd_db, tables->db ? tables->db : thd_db)) + if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db)) return 1; return 0; } @@ -2780,10 +2981,10 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables) } if (options & (REFRESH_TABLES | REFRESH_READ_LOCK)) { - if ((options & REFRESH_READ_LOCK) && thd && ! thd->global_read_lock) + if ((options & REFRESH_READ_LOCK) && thd) { - thd->global_read_lock=1; - thread_safe_increment(global_read_lock,&LOCK_open); + if (lock_global_read_lock(thd)) + return 1; } result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables); } @@ -2844,3 +3045,29 @@ static void refresh_status(void) pthread_mutex_unlock(&LOCK_status); pthread_mutex_unlock(&THR_LOCK_keycache); } + + + /* If pointer is not a null pointer, append filename to it */ + +static bool append_file_to_dir(char **filename_ptr, char *table_name) +{ + char buff[FN_REFLEN],*ptr; + if (!*filename_ptr) + return 0; // nothing to do + + /* Check that the filename is not too long and it's a hard path */ + if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 || + !test_if_hard_path(*filename_ptr)) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr); + return 1; + } + /* Fix is using unix filename format on dos */ + strmov(buff,*filename_ptr); + convert_dirname(buff); + if (!(ptr=sql_alloc(strlen(buff)+strlen(table_name)+1))) + return 1; // End of memory + *filename_ptr=ptr; + strxmov(ptr,buff,table_name,NullS); + return 0; +} diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 7d4a7847eb1..ff1cb125ef8 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha 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 @@ -15,61 +15,143 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Sasha Pachev <sasha@mysql.com> is currently in charge of this file -// Do not mess with it without his permission! #include "mysql_priv.h" #include "sql_repl.h" #include "sql_acl.h" #include "log_event.h" +#include "mini_client.h" #include <thr_alarm.h> #include <my_dir.h> +#define SLAVE_LIST_CHUNK 128 +#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64) + extern const char* any_db; extern pthread_handler_decl(handle_slave,arg); +HASH slave_list; + #ifndef DBUG_OFF int max_binlog_dump_events = 0; // unlimited bool opt_sporadic_binlog_dump_fail = 0; static int binlog_dump_count = 0; #endif +static Slave_log_event* find_slave_event(IO_CACHE* log, + const char* log_file_name, + char* errmsg); + +static uint32* slave_list_key(SLAVE_INFO* si, uint* len, + my_bool not_used __attribute__((unused))) +{ + *len = 4; + return &si->server_id; +} + +static void slave_info_free(void *s) +{ + my_free((byte*)s, MYF(MY_WME)); +} + +void init_slave_list() +{ + hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0, + (hash_get_key) slave_list_key, slave_info_free, 0); + pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST); +} + +void end_slave_list() +{ + pthread_mutex_lock(&LOCK_slave_list); + hash_free(&slave_list); + pthread_mutex_unlock(&LOCK_slave_list); + pthread_mutex_destroy(&LOCK_slave_list); +} + static int fake_rotate_event(NET* net, String* packet, char* log_file_name, const char**errmsg) { - char header[LOG_EVENT_HEADER_LEN]; + char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN]; memset(header, 0, 4); // when does not matter header[EVENT_TYPE_OFFSET] = ROTATE_EVENT; - char* p = strrchr(log_file_name, FN_LIBCHAR); - // find the last slash - if(p) - p++; - else - p = log_file_name; + char* p = log_file_name+dirname_length(log_file_name); uint ident_len = (uint) strlen(p); - ulong event_len = ident_len + sizeof(header); - int4store(header + EVENT_TYPE_OFFSET + 1, server_id); + ulong event_len = ident_len + ROTATE_EVENT_OVERHEAD; + int4store(header + SERVER_ID_OFFSET, server_id); int4store(header + EVENT_LEN_OFFSET, event_len); + int2store(header + FLAGS_OFFSET, 0); + int4store(header + LOG_SEQ_OFFSET, 0); packet->append(header, sizeof(header)); + /* We need to split the next statement because of problem with cxx */ + int4store(buf,4); // tell slave to skip magic number + int4store(buf+4,0); + packet->append(buf, ROTATE_HEADER_LEN); packet->append(p,ident_len); - if(my_net_write(net, (char*)packet->ptr(), packet->length())) - { - *errmsg = "failed on my_net_write()"; - return -1; - } + if (my_net_write(net, (char*)packet->ptr(), packet->length())) + { + *errmsg = "failed on my_net_write()"; + return -1; + } return 0; } +#define get_object(p, obj) \ +{\ + uint len = (uint)*p++; \ + if (p + len > p_end || len >= sizeof(obj)) \ + goto err; \ + strmake(obj,(char*) p,len); \ + p+= len; \ +}\ + + +int register_slave(THD* thd, uchar* packet, uint packet_length) +{ + uint len; + SLAVE_INFO *si, *old_si; + int res = 1; + uchar* p = packet, *p_end = packet + packet_length; + + if (check_access(thd, FILE_ACL, any_db)) + return 1; + + if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME)))) + goto err; + + si->server_id = uint4korr(p); + p += 4; + get_object(p,si->host); + get_object(p,si->user); + get_object(p,si->password); + si->port = uint2korr(p); + pthread_mutex_lock(&LOCK_slave_list); + + if ((old_si = (SLAVE_INFO*)hash_search(&slave_list, + (byte*)&si->server_id, 4))) + hash_delete(&slave_list, (byte*)old_si); + + res = hash_insert(&slave_list, (byte*) si); + pthread_mutex_unlock(&LOCK_slave_list); + return res; + +err: + if (si) + my_free((byte*)si, MYF(MY_WME)); + return res; +} + static int send_file(THD *thd) { NET* net = &thd->net; int fd = -1,bytes, error = 1; char fname[FN_REFLEN+1]; - char *buf; const char *errmsg = 0; int old_timeout; uint packet_len; + char buf[IO_SIZE]; // It's safe to alloc this DBUG_ENTER("send_file"); // the client might be slow loading the data, give him wait_timeout to do @@ -77,40 +159,32 @@ static int send_file(THD *thd) old_timeout = thd->net.timeout; thd->net.timeout = thd->inactive_timeout; - // spare the stack - if(!(buf = alloc_root(&thd->mem_root,IO_SIZE))) - { - errmsg = "Out of memory"; - goto err; - } - // we need net_flush here because the client will not know it needs to send // us the file name until it has processed the load event entry if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error) { - errmsg = "Failed reading file name"; + errmsg = "while reading file name"; goto err; } - *((char*)net->read_pos + packet_len) = 0; // terminate with \0 - //for fn_format - fn_format(fname, (char*)net->read_pos + 1, "", "", 4); + // terminate with \0 for fn_format + *((char*)net->read_pos + packet_len) = 0; + fn_format(fname, (char*) net->read_pos + 1, "", "", 4); // this is needed to make replicate-ignore-db if (!strcmp(fname,"/dev/null")) goto end; - if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0) + if ((fd = my_open(fname, O_RDONLY, MYF(0))) < 0) { - errmsg = "Failed on my_open()"; + errmsg = "on open of file"; goto err; } - while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, - MYF(MY_WME))) > 0) + while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, MYF(0))) > 0) { if (my_net_write(net, buf, bytes)) { - errmsg = "Failed on my_net_write()"; + errmsg = "while writing data to client"; goto err; } } @@ -119,18 +193,18 @@ static int send_file(THD *thd) if (my_net_write(net, "", 0) || net_flush(net) || (my_net_read(net) == packet_error)) { - errmsg = "failed negotiating file transfer close"; + errmsg = "while negotiating file transfer close"; goto err; } error = 0; err: thd->net.timeout = old_timeout; - if(fd >= 0) - (void) my_close(fd, MYF(MY_WME)); + if (fd >= 0) + (void) my_close(fd, MYF(0)); if (errmsg) { - sql_print_error("failed in send_file() : %s", errmsg); + sql_print_error("Failed in send_file() %s", errmsg); DBUG_PRINT("error", (errmsg)); } DBUG_RETURN(error); @@ -138,34 +212,37 @@ static int send_file(THD *thd) File open_binlog(IO_CACHE *log, const char *log_file_name, - const char **errmsg) + const char **errmsg) { File file; char magic[4]; + if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0 || init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME))) { - *errmsg = "Could not open log file"; // This will not be sent + *errmsg = "Could not open log file"; // This will not be sent goto err; } - + if (my_b_read(log, (byte*) magic, sizeof(magic))) { - *errmsg = "I/O error reading binlog magic number"; + *errmsg = "I/O error reading the header from the binary log"; goto err; } - if (memcmp(magic, BINLOG_MAGIC, 4)) + if (memcmp(magic, BINLOG_MAGIC, sizeof(magic))) { - *errmsg = "Binlog has bad magic number, fire your magician"; + *errmsg = "Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL"; goto err; } return file; err: - if (file > 0) + if (file >= 0) + { my_close(file,MYF(0)); - end_io_cache(log); + end_io_cache(log); + } return -1; } @@ -173,26 +250,27 @@ err: void adjust_linfo_offsets(my_off_t purge_offset) { THD *tmp; - + pthread_mutex_lock(&LOCK_thread_count); I_List_iterator<THD> it(threads); - - while((tmp=it++)) - { - LOG_INFO* linfo; - if((linfo = tmp->current_linfo)) - { - pthread_mutex_lock(&linfo->lock); - // no big deal if we just started reading the log - // nothing to adjust - if(linfo->index_file_offset < purge_offset) - linfo->fatal = (linfo->index_file_offset != 0); - else - linfo->index_file_offset -= purge_offset; - pthread_mutex_unlock(&linfo->lock); - } - } + while ((tmp=it++)) + { + LOG_INFO* linfo; + if ((linfo = tmp->current_linfo)) + { + pthread_mutex_lock(&linfo->lock); + /* index file offset can be less that purge offset + only if we just started reading the index file. In that case + we have nothing to adjust + */ + if (linfo->index_file_offset < purge_offset) + linfo->fatal = (linfo->index_file_offset != 0); + else + linfo->index_file_offset -= purge_offset; + pthread_mutex_unlock(&linfo->lock); + } + } pthread_mutex_unlock(&LOCK_thread_count); } @@ -202,21 +280,21 @@ bool log_in_use(const char* log_name) int log_name_len = strlen(log_name) + 1; THD *tmp; bool result = 0; - + pthread_mutex_lock(&LOCK_thread_count); I_List_iterator<THD> it(threads); - - while((tmp=it++)) + + while ((tmp=it++)) + { + LOG_INFO* linfo; + if ((linfo = tmp->current_linfo)) { - LOG_INFO* linfo; - if((linfo = tmp->current_linfo)) - { - pthread_mutex_lock(&linfo->lock); - result = !memcmp(log_name, linfo->log_file_name, log_name_len); - pthread_mutex_unlock(&linfo->lock); - if(result) break; - } - } + pthread_mutex_lock(&linfo->lock); + result = !memcmp(log_name, linfo->log_file_name, log_name_len); + pthread_mutex_unlock(&linfo->lock); + if (result) break; + } + } pthread_mutex_unlock(&LOCK_thread_count); return result; @@ -226,35 +304,35 @@ bool log_in_use(const char* log_name) int purge_master_logs(THD* thd, const char* to_log) { char search_file_name[FN_REFLEN]; + const char* errmsg = 0; + mysql_bin_log.make_log_name(search_file_name, to_log); int res = mysql_bin_log.purge_logs(thd, search_file_name); - const char* errmsg = 0; - switch(res) - { - case 0: break; - case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break; - case LOG_INFO_IO: errmsg = "I/O error reading log index file"; break; - case LOG_INFO_INVALID: errmsg = "Server configuration does not permit \ + + switch(res) { + case 0: break; + case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break; + case LOG_INFO_IO: errmsg = "I/O error reading log index file"; break; + case LOG_INFO_INVALID: errmsg = "Server configuration does not permit \ binlog purge"; break; - case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break; - case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log"; - break; - case LOG_INFO_MEM: errmsg = "Out of memory"; break; - case LOG_INFO_FATAL: errmsg = "Fatal error during purge"; break; - case LOG_INFO_IN_USE: errmsg = "A purgeable log is in use, will not purge"; - break; - default: - errmsg = "Unknown error during purge"; break; - } - - if(errmsg) - { - send_error(&thd->net, 0, errmsg); - return 1; - } + case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break; + case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log"; + break; + case LOG_INFO_MEM: errmsg = "Out of memory"; break; + case LOG_INFO_FATAL: errmsg = "Fatal error during purge"; break; + case LOG_INFO_IN_USE: errmsg = "A purgeable log is in use, will not purge"; + break; + default: errmsg = "Unknown error during purge"; break; + } + + if (errmsg) + { + send_error(&thd->net, 0, errmsg); + return 1; + } else send_ok(&thd->net); - + return 0; } @@ -272,7 +350,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) NET* net = &thd->net; #ifndef DBUG_OFF int left_events = max_binlog_dump_events; -#endif +#endif DBUG_ENTER("mysql_binlog_send"); bzero((char*) &log,sizeof(log)); @@ -282,25 +360,25 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) errmsg = "Master failed COM_BINLOG_DUMP to test if slave can recover"; goto err; } -#endif +#endif - if(!mysql_bin_log.is_open()) + if (!mysql_bin_log.is_open()) { errmsg = "Binary log is not open"; goto err; } - if(!server_id_supplied) - { - errmsg = "Misconfigured master - server id was not set"; - goto err; - } - + if (!server_id_supplied) + { + errmsg = "Misconfigured master - server id was not set"; + goto err; + } + if (log_ident[0]) mysql_bin_log.make_log_name(search_file_name, log_ident); else search_file_name[0] = 0; - + linfo.index_file_offset = 0; thd->current_linfo = &linfo; @@ -315,20 +393,21 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) if (pos < 4) { - errmsg = "Client requested master to start repliction from impossible position.\n"; + errmsg = "Client requested master to start repliction from \ +impossible position"; goto err; } - + my_b_seek(&log, pos); // Seek will done on next read packet->length(0); - packet->append("\0", 1); // we need to start a packet with something other than 255 // to distiquish it from error + packet->append("\0", 1); - // tell the client log name with a fake rotate_event // if we are at the start of the log - if(pos == 4) + if (pos == 4) { + // tell the client log name with a fake rotate_event if (fake_rotate_event(net, packet, log_file_name, &errmsg)) goto err; packet->length(0); @@ -338,17 +417,17 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) while (!net->error && net->vio != 0 && !thd->killed) { pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); - + while (!(error = Log_event::read_log_event(&log, packet, log_lock))) { #ifndef DBUG_OFF - if(max_binlog_dump_events && !left_events--) + if (max_binlog_dump_events && !left_events--) { net_flush(net); errmsg = "Debugging binlog dump abort"; goto err; } -#endif +#endif if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -358,7 +437,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) (*packet)[LOG_EVENT_OFFSET+1] )); if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) { - if(send_file(thd)) + if (send_file(thd)) { errmsg = "failed in send_file()"; goto err; @@ -367,15 +446,14 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) packet->length(0); packet->append("\0",1); } - + if (error != LOG_READ_EOF) { - switch(error) - { - case LOG_READ_BOGUS: + switch(error) { + case LOG_READ_BOGUS: errmsg = "bogus data in log event"; break; - case LOG_READ_TOO_LARGE: + case LOG_READ_TOO_LARGE: errmsg = "log event entry exceeded max_allowed_packet -\ increase max_allowed_packet on master"; break; @@ -395,12 +473,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) goto err; } - if(!(flags & BINLOG_DUMP_NON_BLOCK) && + if (!(flags & BINLOG_DUMP_NON_BLOCK) && mysql_bin_log.is_active(log_file_name)) + { // block until there is more data in the log // unless non-blocking mode requested - { - if(net_flush(net)) + if (net_flush(net)) { errmsg = "failed on net_flush()"; goto err; @@ -422,13 +500,13 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) bool read_packet = 0, fatal_error = 0; #ifndef DBUG_OFF - if(max_binlog_dump_events && !left_events--) + if (max_binlog_dump_events && !left_events--) { net_flush(net); errmsg = "Debugging binlog dump abort"; goto err; } -#endif +#endif // no one will update the log while we are reading // now, but we'll be quick and just read one record @@ -458,18 +536,18 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) thd->proc_info= proc_info; pthread_mutex_unlock(&thd->mysys_var->mutex); - if(read_packet) + if (read_packet) { thd->proc_info = "sending update to slave"; - if(my_net_write(net, (char*)packet->ptr(), packet->length()) ) + if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; goto err; } - if((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) + if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) { - if(send_file(thd)) + if (send_file(thd)) { errmsg = "failed in send_file()"; goto err; @@ -481,7 +559,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) // we hit EOF pretty quick } - if(fatal_error) + if (fatal_error) { errmsg = "error reading log entry"; goto err; @@ -494,8 +572,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) bool loop_breaker = 0; // need this to break out of the for loop from switch thd->proc_info = "switching to next log"; - switch(mysql_bin_log.find_next_log(&linfo)) - { + switch (mysql_bin_log.find_next_log(&linfo)) { case LOG_INFO_EOF: loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); break; @@ -506,12 +583,12 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) goto err; } - if(loop_breaker) + if (loop_breaker) break; end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); - + // fake Rotate_log event just in case it did not make it to the log // otherwise the slave make get confused about the offset if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 || @@ -525,13 +602,14 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - + send_eof(&thd->net); thd->proc_info = "waiting to finalize termination"; pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; + err: thd->proc_info = "waiting to finalize termination"; end_io_cache(&log); @@ -551,50 +629,52 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) int start_slave(THD* thd , bool net_report) { - if(!thd) thd = current_thd; - NET* net = &thd->net; int slave_errno = 0; + if (!thd) thd = current_thd; + NET* net = &thd->net; + if (check_access(thd, PROCESS_ACL, any_db)) return 1; pthread_mutex_lock(&LOCK_slave); - if(!slave_running) + if (!slave_running) + { + if (init_master_info(&glob_mi)) + slave_errno = ER_MASTER_INFO; + else if (server_id_supplied && *glob_mi.host) { - if(init_master_info(&glob_mi)) - slave_errno = ER_MASTER_INFO; - else if(server_id_supplied && *glob_mi.host) - { - pthread_t hThread; - if(pthread_create(&hThread, &connection_attrib, handle_slave, 0)) - { - slave_errno = ER_SLAVE_THREAD; - } - while(!slave_running) // slave might already be running by now - pthread_cond_wait(&COND_slave_start, &LOCK_slave); - } - else - slave_errno = ER_BAD_SLAVE; + pthread_t hThread; + if (pthread_create(&hThread, &connection_attrib, handle_slave, 0)) + { + slave_errno = ER_SLAVE_THREAD; + } + while (!slave_running) // slave might already be running by now + pthread_cond_wait(&COND_slave_start, &LOCK_slave); } + else + slave_errno = ER_BAD_SLAVE; + } else slave_errno = ER_SLAVE_MUST_STOP; pthread_mutex_unlock(&LOCK_slave); - if(slave_errno) - { - if(net_report) send_error(net, slave_errno); - return 1; - } - else if(net_report) + if (slave_errno) + { + if (net_report) send_error(net, slave_errno); + return 1; + } + else if (net_report) send_ok(net); return 0; } + int stop_slave(THD* thd, bool net_report ) { - if(!thd) thd = current_thd; - NET* net = &thd->net; int slave_errno = 0; - + if (!thd) thd = current_thd; + NET* net = &thd->net; + if (check_access(thd, PROCESS_ACL, any_db)) return 1; @@ -605,7 +685,7 @@ int stop_slave(THD* thd, bool net_report ) thr_alarm_kill(slave_real_id); #ifdef SIGNAL_WITH_VIO_CLOSE slave_thd->close_active_vio(); -#endif +#endif // do not abort the slave in the middle of a query, so we do not set // thd->killed for the slave thread thd->proc_info = "waiting for slave to die"; @@ -639,17 +719,19 @@ int stop_slave(THD* thd, bool net_report ) pthread_mutex_unlock(&LOCK_slave); thd->proc_info = 0; - if(slave_errno) - { - if(net_report) send_error(net, slave_errno); - return 1; - } - else if(net_report) + if (slave_errno) + { + if (net_report) + send_error(net, slave_errno); + return 1; + } + else if (net_report) send_ok(net); return 0; } + void reset_slave() { MY_STAT stat_area; @@ -657,115 +739,115 @@ void reset_slave() bool slave_was_running ; pthread_mutex_lock(&LOCK_slave); - if((slave_was_running = slave_running)) - { + if ((slave_was_running = slave_running)) + { pthread_mutex_unlock(&LOCK_slave); stop_slave(0,0); - } + } else pthread_mutex_unlock(&LOCK_slave); - + end_master_info(&glob_mi); - fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32); - if(my_stat(fname, &stat_area, MYF(0))) - if(my_delete(fname, MYF(MY_WME))) - return; - if(slave_was_running) + fn_format(fname, master_info_file, mysql_data_home, "", 4+32); + if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME))) + return; + if (slave_was_running) start_slave(0,0); } + void kill_zombie_dump_threads(uint32 slave_server_id) { pthread_mutex_lock(&LOCK_thread_count); I_List_iterator<THD> it(threads); THD *tmp; - while((tmp=it++)) + while ((tmp=it++)) + { + if (tmp->command == COM_BINLOG_DUMP && + tmp->server_id == slave_server_id) { - if(tmp->command == COM_BINLOG_DUMP && - tmp->server_id == slave_server_id) - { - // here we do not call kill_one_thread() - // it will be slow because it will iterate through the list - // again. Plus it double-locks LOCK_thread_count, which - // make safe_mutex complain and abort - // so we just to our own thread murder - - thr_alarm_kill(tmp->real_id); - tmp->killed = 1; - tmp->mysys_var->abort = 1; - pthread_mutex_lock(&tmp->mysys_var->mutex); - if(tmp->mysys_var->current_cond) - { - pthread_mutex_lock(tmp->mysys_var->current_mutex); - pthread_cond_broadcast(tmp->mysys_var->current_cond); - pthread_mutex_unlock(tmp->mysys_var->current_mutex); - } - pthread_mutex_unlock(&tmp->mysys_var->mutex); - } - } - + /* + Here we do not call kill_one_thread() as + it will be slow because it will iterate through the list + again. Plus it double-locks LOCK_tread_count, which + make safe_mutex complain and abort. + We just to do kill the thread ourselves. + */ + + thr_alarm_kill(tmp->real_id); + tmp->killed = 1; + tmp->mysys_var->abort = 1; + pthread_mutex_lock(&tmp->mysys_var->mutex); + if (tmp->mysys_var->current_cond) + { + pthread_mutex_lock(tmp->mysys_var->current_mutex); + pthread_cond_broadcast(tmp->mysys_var->current_cond); + pthread_mutex_unlock(tmp->mysys_var->current_mutex); + } + pthread_mutex_unlock(&tmp->mysys_var->mutex); + } + } pthread_mutex_unlock(&LOCK_thread_count); } + int change_master(THD* thd) { bool slave_was_running; // kill slave thread pthread_mutex_lock(&LOCK_slave); - if((slave_was_running = slave_running)) - { - abort_slave = 1; - thr_alarm_kill(slave_real_id); - thd->proc_info = "waiting for slave to die"; - while(slave_running) - pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done - } + if ((slave_was_running = slave_running)) + { + abort_slave = 1; + thr_alarm_kill(slave_real_id); + thd->proc_info = "waiting for slave to die"; + while (slave_running) + pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done + } pthread_mutex_unlock(&LOCK_slave); thd->proc_info = "changing master"; LEX_MASTER_INFO* lex_mi = &thd->lex.mi; - if(init_master_info(&glob_mi)) - { - send_error(&thd->net, 0, "Could not initialize master info"); - return 1; - } - + if (init_master_info(&glob_mi)) + { + send_error(&thd->net, 0, "Could not initialize master info"); + return 1; + } + pthread_mutex_lock(&glob_mi.lock); - if((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) - { - // if we change host or port, we must reset the postion - glob_mi.log_file_name[0] = 0; - glob_mi.pos = 4; // skip magic number - glob_mi.pending = 0; - } + if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) + { + // if we change host or port, we must reset the postion + glob_mi.log_file_name[0] = 0; + glob_mi.pos = 4; // skip magic number + glob_mi.pending = 0; + } - if(lex_mi->log_file_name) + if (lex_mi->log_file_name) strmake(glob_mi.log_file_name, lex_mi->log_file_name, sizeof(glob_mi.log_file_name)); - if(lex_mi->pos) + if (lex_mi->pos) { glob_mi.pos = lex_mi->pos; glob_mi.pending = 0; } - - if(lex_mi->host) - { - strmake(glob_mi.host, lex_mi->host, sizeof(glob_mi.host)); - } - if(lex_mi->user) + + if (lex_mi->host) + strmake(glob_mi.host, lex_mi->host, sizeof(glob_mi.host)); + if (lex_mi->user) strmake(glob_mi.user, lex_mi->user, sizeof(glob_mi.user)); - if(lex_mi->password) + if (lex_mi->password) strmake(glob_mi.password, lex_mi->password, sizeof(glob_mi.password)); - if(lex_mi->port) + if (lex_mi->port) glob_mi.port = lex_mi->port; - if(lex_mi->connect_retry) + if (lex_mi->connect_retry) glob_mi.connect_retry = lex_mi->connect_retry; flush_master_info(&glob_mi); pthread_mutex_unlock(&glob_mi.lock); thd->proc_info = "starting slave"; - if(slave_was_running) + if (slave_was_running) start_slave(0,0); thd->proc_info = 0; @@ -773,9 +855,10 @@ int change_master(THD* thd) return 0; } + void reset_master() { - if(!mysql_bin_log.is_open()) + if (!mysql_bin_log.is_open()) { my_error(ER_FLUSH_MASTER_BINLOG_CLOSED, MYF(ME_BELL+ME_WAITTANG)); return; @@ -794,9 +877,400 @@ void reset_master() mysql_bin_log.close(1); // exiting close my_delete(mysql_bin_log.get_index_fname(), MYF(MY_WME)); mysql_bin_log.open(opt_bin_logname,LOG_BIN); +} + + +int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, + const char* log_file_name2, ulonglong log_pos2) +{ + int res; + if ((res = strcmp(log_file_name1, log_file_name2))) + return res; + if (log_pos1 > log_pos2) + return 1; + else if (log_pos1 == log_pos2) + return 0; + return -1; +} + + +static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi) +{ + return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name, + mi->pos); +} + +static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg) +{ + uint32 log_seq = mi->last_log_seq; + uint32 target_server_id = mi->server_id; + + for (;;) + { + Log_event* ev; + if (!(ev = Log_event::read_log_event(log, 0))) + { + if (log->error > 0) + strmov(errmsg, "Binary log truncated in the middle of event"); + else if (log->error < 0) + strmov(errmsg, "I/O error reading binary log"); + else + strmov(errmsg, "Could not find target event in the binary log"); + return 1; + } + + if (ev->log_seq == log_seq && ev->server_id == target_server_id) + { + delete ev; + mi->pos = my_b_tell(log); + return 0; + } + + delete ev; + } +} + + +int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg) +{ + LOG_INFO linfo; + char search_file_name[FN_REFLEN],last_log_name[FN_REFLEN]; + IO_CACHE log, last_log; + File file = -1, last_file = -1; + pthread_mutex_t *log_lock; + const char* errmsg_p; + Slave_log_event* sev = 0; + my_off_t last_pos = 0; + int error = 1; + int cmp_res; + LINT_INIT(cmp_res); + + if (!mysql_bin_log.is_open()) + { + strmov(errmsg,"Binary log is not open"); + return 1; + } + + if (!server_id_supplied) + { + strmov(errmsg, "Misconfigured master - server id was not set"); + return 1; + } + + linfo.index_file_offset = 0; + + + search_file_name[0] = 0; + + if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + { + strmov(errmsg,"Could not find first log"); + return 1; + } + thd->current_linfo = &linfo; + + bzero((char*) &log,sizeof(log)); + log_lock = mysql_bin_log.get_log_lock(); + pthread_mutex_lock(log_lock); + + for (;;) + { + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0) + { + strmov(errmsg, errmsg_p); + goto err; + } + + if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg))) + goto err; + + cmp_res = cmp_master_pos(sev, mi); + delete sev; + + if (!cmp_res) + { + /* Copy basename */ + fn_format(mi->log_file_name, linfo.log_file_name, "","",1); + mi->pos = my_b_tell(&log); + goto mi_inited; + } + else if (cmp_res > 0) + { + if (!last_pos) + { + strmov(errmsg, + "Slave event in first log points past the target position"); + goto err; + } + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); + if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0, + MYF(MY_WME))) + { + errmsg[0] = 0; + goto err; + } + break; + } + + strmov(last_log_name, linfo.log_file_name); + last_pos = my_b_tell(&log); + + switch (mysql_bin_log.find_next_log(&linfo)) { + case LOG_INFO_EOF: + if (last_file >= 0) + (void)my_close(last_file, MYF(MY_WME)); + last_file = -1; + goto found_log; + case 0: + break; + default: + strmov(errmsg, "Error reading log index"); + goto err; + } + + end_io_cache(&log); + if (last_file >= 0) + (void) my_close(last_file, MYF(MY_WME)); + last_file = file; + } + +found_log: + my_b_seek(&log, last_pos); + if (find_target_pos(mi,&log,errmsg)) + goto err; + fn_format(mi->log_file_name, last_log_name, "","",1); /* Copy basename */ + +mi_inited: + error = 0; +err: + pthread_mutex_unlock(log_lock); + end_io_cache(&log); + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = 0; + pthread_mutex_unlock(&LOCK_thread_count); + if (file >= 0) + (void) my_close(file, MYF(MY_WME)); + if (last_file >= 0 && last_file != file) + (void) my_close(last_file, MYF(MY_WME)); + + return error; +} + +// caller must delete result when done +static Slave_log_event* find_slave_event(IO_CACHE* log, + const char* log_file_name, + char* errmsg) +{ + Log_event* ev; + if (!(ev = Log_event::read_log_event(log, 0))) + { + my_snprintf(errmsg, SLAVE_ERRMSG_SIZE, + "Error reading start event in log '%s'", + (char*)log_file_name); + return 0; + } + delete ev; + + if (!(ev = Log_event::read_log_event(log, 0))) + { + my_snprintf(errmsg, SLAVE_ERRMSG_SIZE, + "Error reading slave event in log '%s'", + (char*)log_file_name); + return 0; + } + + if (ev->get_type_code() != SLAVE_EVENT) + { + my_snprintf(errmsg, SLAVE_ERRMSG_SIZE, + "Second event in log '%s' is not slave event", + (char*)log_file_name); + delete ev; + return 0; + } + + return (Slave_log_event*)ev; +} + + +int show_new_master(THD* thd) +{ + DBUG_ENTER("show_new_master"); + List<Item> field_list; + char errmsg[SLAVE_ERRMSG_SIZE]; + LEX_MASTER_INFO* lex_mi = &thd->lex.mi; + + errmsg[0]=0; // Safety + if (translate_master(thd, lex_mi, errmsg)) + { + if (errmsg[0]) + net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND, + "SHOW NEW MASTER", errmsg); + else + send_error(&thd->net, 0); + + DBUG_RETURN(1); + } + else + { + String* packet = &thd->packet; + field_list.push_back(new Item_empty_string("Log_name", 20)); + field_list.push_back(new Item_empty_string("Log_pos", 20)); + if (send_fields(thd, field_list, 1)) + DBUG_RETURN(-1); + packet->length(0); + net_store_data(packet, lex_mi->log_file_name); + net_store_data(packet, (longlong)lex_mi->pos); + if (my_net_write(&thd->net, packet->ptr(), packet->length())) + DBUG_RETURN(-1); + send_eof(&thd->net); + DBUG_RETURN(0); + } + +} + +int show_binlog_events(THD* thd) +{ + DBUG_ENTER("show_binlog_events"); + List<Item> field_list; + const char* errmsg = 0; + IO_CACHE log; + File file = -1; + + Log_event::init_show_field_list(&field_list); + if (send_fields(thd, field_list, 1)) + DBUG_RETURN(-1); + + if (mysql_bin_log.is_open()) + { + LOG_INFO linfo; + char search_file_name[FN_REFLEN]; + LEX_MASTER_INFO* lex_mi = &thd->lex.mi; + uint event_count, limit_start, limit_end; + const char* log_file_name = lex_mi->log_file_name; + Log_event* ev; + ulong pos = (ulong) lex_mi->pos; + + limit_start = thd->lex.select->offset_limit; + limit_end = thd->lex.select->select_limit + limit_start; + + if (log_file_name) + mysql_bin_log.make_log_name(search_file_name, log_file_name); + else + search_file_name[0] = 0; + + linfo.index_file_offset = 0; + thd->current_linfo = &linfo; + + if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + { + errmsg = "Could not find target log"; + goto err; + } + + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) + goto err; + + if (pos < 4) + { + errmsg = "Invalid log position"; + goto err; + } + + pthread_mutex_lock(mysql_bin_log.get_log_lock()); + my_b_seek(&log, pos); + for (event_count = 0; (ev = Log_event::read_log_event(&log, 0)); ) + { + if (event_count >= limit_start && + ev->net_send(thd, linfo.log_file_name, pos)) + { + errmsg = "Net error"; + delete ev; + pthread_mutex_unlock(mysql_bin_log.get_log_lock()); + goto err; + } + + pos = my_b_tell(&log); + delete ev; + + if (++event_count >= limit_end) + break; + } + + if (event_count < limit_end && log.error) + { + errmsg = "Wrong offset or I/O error"; + goto err; + } + + pthread_mutex_unlock(mysql_bin_log.get_log_lock()); + } + +err: + if (file >= 0) + { + end_io_cache(&log); + (void) my_close(file, MYF(MY_WME)); + } + + if (errmsg) + { + net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND, + "SHOW BINLOG EVENTS", errmsg); + DBUG_RETURN(1); + } + + send_eof(&thd->net); + DBUG_RETURN(0); +} + + +int show_slave_hosts(THD* thd) +{ + List<Item> field_list; + NET* net = &thd->net; + String* packet = &thd->packet; + DBUG_ENTER("show_slave_hosts"); + + field_list.push_back(new Item_empty_string("Server_id", 20)); + field_list.push_back(new Item_empty_string("Host", 20)); + if (opt_show_slave_auth_info) + { + field_list.push_back(new Item_empty_string("User",20)); + field_list.push_back(new Item_empty_string("Password",20)); + } + field_list.push_back(new Item_empty_string("Port",20)); + + if (send_fields(thd, field_list, 1)) + DBUG_RETURN(-1); + + pthread_mutex_lock(&LOCK_slave_list); + + for (uint i = 0; i < slave_list.records; ++i) + { + SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i); + packet->length(0); + net_store_data(packet, si->server_id); + net_store_data(packet, si->host); + if (opt_show_slave_auth_info) + { + net_store_data(packet, si->user); + net_store_data(packet, si->password); + } + net_store_data(packet, (uint)si->port); + if (my_net_write(net, (char*)packet->ptr(), packet->length())) + { + pthread_mutex_unlock(&LOCK_slave_list); + DBUG_RETURN(-1); + } + } + pthread_mutex_unlock(&LOCK_slave_list); + send_eof(net); + DBUG_RETURN(0); } + int show_binlog_info(THD* thd) { DBUG_ENTER("show_binlog_info"); @@ -806,36 +1280,37 @@ int show_binlog_info(THD* thd) field_list.push_back(new Item_empty_string("Binlog_do_db",20)); field_list.push_back(new Item_empty_string("Binlog_ignore_db",20)); - if(send_fields(thd, field_list, 1)) + if (send_fields(thd, field_list, 1)) DBUG_RETURN(-1); String* packet = &thd->packet; packet->length(0); - if(mysql_bin_log.is_open()) - { - LOG_INFO li; - mysql_bin_log.get_current_log(&li); - int dir_len = dirname_length(li.log_file_name); - net_store_data(packet, li.log_file_name + dir_len); - net_store_data(packet, (longlong)li.pos); - net_store_data(packet, &binlog_do_db); - net_store_data(packet, &binlog_ignore_db); - } + if (mysql_bin_log.is_open()) + { + LOG_INFO li; + mysql_bin_log.get_current_log(&li); + int dir_len = dirname_length(li.log_file_name); + net_store_data(packet, li.log_file_name + dir_len); + net_store_data(packet, (longlong)li.pos); + net_store_data(packet, &binlog_do_db); + net_store_data(packet, &binlog_ignore_db); + } else - { - net_store_null(packet); - net_store_null(packet); - net_store_null(packet); - net_store_null(packet); - } + { + net_store_null(packet); + net_store_null(packet); + net_store_null(packet); + net_store_null(packet); + } - if(my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) + if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); send_eof(&thd->net); DBUG_RETURN(0); } + int show_binlogs(THD* thd) { const char* errmsg = 0; @@ -846,20 +1321,20 @@ int show_binlogs(THD* thd) String* packet = &thd->packet; IO_CACHE io_cache; uint length; - - if(!mysql_bin_log.is_open()) + + if (!mysql_bin_log.is_open()) { errmsg = "binlog is not open"; goto err; } field_list.push_back(new Item_empty_string("Log_name", 128)); - if(send_fields(thd, field_list, 1)) + if (send_fields(thd, field_list, 1)) { sql_print_error("Failed in send_fields"); return 1; } - + mysql_bin_log.lock_index(); index_file = mysql_bin_log.get_index_file(); if (index_file < 0) @@ -879,7 +1354,7 @@ int show_binlogs(THD* thd) int dir_len = dirname_length(fname); packet->length(0); net_store_data(packet, fname + dir_len, length-dir_len); - if(my_net_write(net, (char*) packet->ptr(), packet->length())) + if (my_net_write(net, (char*) packet->ptr(), packet->length())) { sql_print_error("Failed in my_net_write"); end_io_cache(&io_cache); @@ -887,10 +1362,10 @@ int show_binlogs(THD* thd) return 1; } } - + mysql_bin_log.unlock_index(); end_io_cache(&io_cache); - send_eof(net); + send_eof(net); return 0; err2: @@ -902,4 +1377,258 @@ err: } +int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) +{ + if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, + mi->port, 0, 0)) + { + sql_print_error("Connection to master failed: %s", + mc_mysql_error(mysql)); + return 1; + } + return 0; +} + + +static inline void cleanup_mysql_results(MYSQL_RES* db_res, + MYSQL_RES** cur, MYSQL_RES** start) +{ + for( ; cur >= start; --cur) + { + if (*cur) + mc_mysql_free_result(*cur); + } + mc_mysql_free_result(db_res); +} + + +static inline int fetch_db_tables(THD* thd, MYSQL* mysql, const char* db, + MYSQL_RES* table_res) +{ + MYSQL_ROW row; + + for( row = mc_mysql_fetch_row(table_res); row; + row = mc_mysql_fetch_row(table_res)) + { + TABLE_LIST table; + const char* table_name = row[0]; + int error; + if (table_rules_on) + { + table.next = 0; + table.db = (char*)db; + table.real_name = (char*)table_name; + table.updating = 1; + if (!tables_ok(thd, &table)) + continue; + } + + if ((error = fetch_nx_table(thd, db, table_name, &glob_mi, mysql))) + return error; + } + + return 0; +} + + +int load_master_data(THD* thd) +{ + MYSQL mysql; + MYSQL_RES* master_status_res = 0; + bool slave_was_running = 0; + int error = 0; + + mc_mysql_init(&mysql); + + // we do not want anyone messing with the slave at all for the entire + // duration of the data load; + pthread_mutex_lock(&LOCK_slave); + + // first, kill the slave + if ((slave_was_running = slave_running)) + { + abort_slave = 1; + thr_alarm_kill(slave_real_id); + thd->proc_info = "waiting for slave to die"; + while (slave_running) + pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done + } + + + if (connect_to_master(thd, &mysql, &glob_mi)) + { + net_printf(&thd->net, error = ER_CONNECT_TO_MASTER, + mc_mysql_error(&mysql)); + goto err; + } + + // now that we are connected, get all database and tables in each + { + MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; + uint num_dbs; + MYSQL_ROW row; + + if (mc_mysql_query(&mysql, "show databases", 0) || + !(db_res = mc_mysql_store_result(&mysql))) + { + net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + mc_mysql_error(&mysql)); + goto err; + } + + if (!(num_dbs = mc_mysql_num_rows(db_res))) + goto err; + // in theory, the master could have no databases at all + // and run with skip-grant + + if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*)))) + { + net_printf(&thd->net, error = ER_OUTOFMEMORY); + goto err; + } + + // this is a temporary solution until we have online backup + // capabilities - to be replaced once online backup is working + // we wait to issue FLUSH TABLES WITH READ LOCK for as long as we + // can to minimize the lock time + if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) || + mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) || + !(master_status_res = mc_mysql_store_result(&mysql))) + { + net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + mc_mysql_error(&mysql)); + goto err; + } + + // go through every table in every database, and if the replication + // rules allow replicating it, get it + + table_res_end = table_res + num_dbs; + + for(cur_table_res = table_res; cur_table_res < table_res_end; + cur_table_res++) + { + // since we know how many rows we have, this can never be NULL + MYSQL_ROW row = mc_mysql_fetch_row(db_res); + char* db = row[0]; + int drop_error; + + /* + Do not replicate databases excluded by rules + also skip mysql database - in most cases the user will + mess up and not exclude mysql database with the rules when + he actually means to - in this case, he is up for a surprise if + his priv tables get dropped and downloaded from master + TO DO - add special option, not enabled + by default, to allow inclusion of mysql database into load + data from master + */ + + if (!db_ok(db, replicate_do_db, replicate_ignore_db) || + !strcmp(db,"mysql")) + { + *cur_table_res = 0; + continue; + } + + if ((drop_error = mysql_rm_db(0, db, 1)) || + mysql_create_db(0, db, 0)) + { + error = (drop_error) ? ER_DB_DROP_DELETE : ER_CANT_CREATE_DB; + net_printf(&thd->net, error, db, my_error); + cleanup_mysql_results(db_res, cur_table_res - 1, table_res); + goto err; + } + + if (mc_mysql_select_db(&mysql, db) || + mc_mysql_query(&mysql, "show tables", 0) || + !(*cur_table_res = mc_mysql_store_result(&mysql))) + { + net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + mc_mysql_error(&mysql)); + cleanup_mysql_results(db_res, cur_table_res - 1, table_res); + goto err; + } + + if ((error = fetch_db_tables(thd, &mysql, db, *cur_table_res))) + { + // we do not report the error - fetch_db_tables handles it + cleanup_mysql_results(db_res, cur_table_res, table_res); + goto err; + } + } + + cleanup_mysql_results(db_res, cur_table_res - 1, table_res); + + // adjust position in the master + if (master_status_res) + { + MYSQL_ROW row = mc_mysql_fetch_row(master_status_res); + + /* + We need this check because the master may not be running with + log-bin, but it will still allow us to do all the steps + of LOAD DATA FROM MASTER - no reason to forbid it, really, + although it does not make much sense for the user to do it + */ + if (row[0] && row[1]) + { + strmake(glob_mi.log_file_name, row[0], sizeof(glob_mi.log_file_name)); + glob_mi.pos = atoi(row[1]); // atoi() is ok, since offset is <= 1GB + if (glob_mi.pos < 4) + glob_mi.pos = 4; // don't hit the magic number + glob_mi.pending = 0; + flush_master_info(&glob_mi); + } + + mc_mysql_free_result(master_status_res); + } + + if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0)) + { + net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + mc_mysql_error(&mysql)); + goto err; + } + } + +err: + pthread_mutex_unlock(&LOCK_slave); + if (slave_was_running) + start_slave(0, 0); + mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init() + if (!error) + send_ok(&thd->net); + + return error; +} + +int log_loaded_block(IO_CACHE* file) +{ + LOAD_FILE_INFO* lf_info; + uint block_len ; + if (!(block_len = file->rc_end - file->buffer)) + return 0; + lf_info = (LOAD_FILE_INFO*)file->arg; + if (lf_info->last_pos_in_file != HA_POS_ERROR && + lf_info->last_pos_in_file >= file->pos_in_file) + return 0; + lf_info->last_pos_in_file = file->pos_in_file; + if (lf_info->wrote_create_file) + { + Append_block_log_event a(lf_info->thd, file->buffer,block_len); + mysql_bin_log.write(&a); + } + else + { + Create_file_log_event c(lf_info->thd,lf_info->ex,lf_info->db, + lf_info->table_name, *lf_info->fields, + lf_info->handle_dup, file->buffer, + block_len); + mysql_bin_log.write(&c); + lf_info->wrote_create_file = 1; + } + return 0; +} + diff --git a/sql/sql_repl.h b/sql/sql_repl.h index c6a79ec4650..3445cd67b42 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -3,6 +3,17 @@ #include "slave.h" +typedef struct st_slave_info +{ + uint32 server_id; + char host[HOSTNAME_LENGTH+1]; + char user[USERNAME_LENGTH+1]; + char password[HASH_PASSWORD_LENGTH+1]; + uint16 port; +} SLAVE_INFO; + +extern bool opt_show_slave_auth_info, opt_old_rpl_compat; +extern HASH slave_list; extern char* master_host; extern my_string opt_bin_logname, master_info_file; extern uint32 server_id; @@ -19,9 +30,20 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, int start_slave(THD* thd = 0, bool net_report = 1); int stop_slave(THD* thd = 0, bool net_report = 1); +int load_master_data(THD* thd); +int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi); int change_master(THD* thd); +int show_new_master(THD* thd); +int show_slave_hosts(THD* thd); +int show_binlog_events(THD* thd); +int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg); +int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, + const char* log_file_name2, ulonglong log_pos2); void reset_slave(); void reset_master(); +void init_slave_list(); +void end_slave_list(); +int register_slave(THD* thd, uchar* packet, uint packet_length); int purge_master_logs(THD* thd, const char* to_log); bool log_in_use(const char* log_name); void adjust_linfo_offsets(my_off_t purge_offset); @@ -29,4 +51,19 @@ int show_binlogs(THD* thd); extern int init_master_info(MASTER_INFO* mi); void kill_zombie_dump_threads(uint32 slave_server_id); +typedef struct st_load_file_info +{ + THD* thd; + sql_exchange* ex; + List <Item> *fields; + enum enum_duplicates handle_dup; + char* db; + char* table_name; + bool wrote_create_file; + my_off_t last_pos_in_file; +} LOAD_FILE_INFO; + +int log_loaded_block(IO_CACHE* file); + #endif + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b6c261d1463..38aedbb4193 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -69,7 +69,7 @@ static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool open_tmp_table(TABLE *table); static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, - uint options); + ulong options); static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, Procedure *proc); static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); @@ -105,7 +105,7 @@ static COND *make_cond_for_table(COND *cond,table_map table, static Item* part_of_refkey(TABLE *form,Field *field); static uint find_shortest_key(TABLE *table, key_map usable_keys); static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, - ha_rows select_limit); + ha_rows select_limit, bool no_changes); static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit); static bool fix_having(JOIN *join, Item **having); static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields, @@ -143,6 +143,34 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct); static void describe_info(THD *thd, const char *info); +/* + This handles SELECT with and without UNION +*/ + +int handle_select(THD *thd, LEX *lex, select_result *result) +{ + int res; + register SELECT_LEX *select_lex = &lex->select_lex; + if (select_lex->next) + res=mysql_union(thd,lex,result); + else + res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, + select_lex->item_list, + select_lex->where, + select_lex->ftfunc_list, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) lex->proc_list.first, + select_lex->options | thd->options, + result); + if (res && result) + result->abort(); + delete result; + return res; +} + + /***************************************************************************** ** check fields, find best join, do the select and output fields. ** mysql_select assumes that all tables are allready opened @@ -152,12 +180,12 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, List<Item_func_match> &ftfuncs, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - uint select_options,select_result *result) + ulong select_options,select_result *result) { TABLE *tmp_table; int error,tmp; bool need_tmp,hidden_group_fields; - bool simple_order,simple_group,no_order; + bool simple_order,simple_group,no_order, skip_sort_order; Item::cond_result cond_value; SQL_SELECT *select; DYNAMIC_ARRAY keyuse; @@ -172,13 +200,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, select_distinct=test(select_options & SELECT_DISTINCT); tmp_table=0; select=0; - no_order=0; + no_order=skip_sort_order=0; bzero((char*) &keyuse,sizeof(keyuse)); thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields if (setup_tables(tables) || - setup_fields(thd,tables,fields,1,&all_fields) || + setup_fields(thd,tables,fields,1,&all_fields,1) || setup_conds(thd,tables,&conds) || setup_order(thd,tables,fields,all_fields,order) || setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields)) @@ -207,7 +235,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, if (!group) { uint flag=0; - List_iterator<Item> it(fields); + List_iterator_fast<Item> it(fields); Item *item; while ((item= it++)) { @@ -276,7 +304,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, count_field_types(&join.tmp_table_param,all_fields,0); join.const_tables=0; join.having=0; + join.do_send_rows = 1; join.group= group != 0; + join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR : + thd->select_limit); #ifdef RESTRICTED_GROUP if (join.sum_func_count && !group && (join.func_count || join.field_count)) @@ -358,7 +389,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, result->send_fields(fields,1); if (!having || having->val_int()) { - if (result->send_data(fields)) + if (join.do_send_rows && result->send_data(fields)) { result->send_error(0,NullS); /* purecov: inspected */ error=1; @@ -370,7 +401,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, error=(int) result->send_eof(); } delete procedure; - DBUG_RETURN(0); + DBUG_RETURN(error); } error = -1; @@ -382,6 +413,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, thd->fatal_error) goto err; thd->proc_info="preparing"; + result->initialize_tables(&join); if ((tmp=join_read_const_tables(&join)) > 0) goto err; if (tmp && !(select_options & SELECT_DESCRIBE)) @@ -399,7 +431,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, error= 1; /* purecov: inspected */ goto err; /* purecov: inspected */ } - if (join.const_tables && !thd->locked_tables) + if (join.const_tables && !thd->locked_tables && + !(select_options & SELECT_NO_UNLOCK)) { TABLE **table, **end; for (table=join.table, end=table + join.const_tables ; @@ -448,7 +481,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, select_distinct=0; } else if (select_distinct && join.tables - join.const_tables == 1 && - (order || thd->select_limit == HA_POS_ERROR)) + (thd->select_limit == HA_POS_ERROR || + (join.select_options & OPTION_FOUND_ROWS) || + order && + !(skip_sort_order=test_if_skip_sort_order(&join.join_tab[join.const_tables], order, thd->select_limit,1)))) { if ((group=create_distinct_group(order,fields))) { @@ -493,8 +529,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, (group && order) || test(select_options & OPTION_BUFFER_RESULT))); - make_join_readinfo(&join, (select_options & SELECT_DESCRIBE) | - (ftfuncs.elements ? 0 : SELECT_USE_CACHE)); // No cache for MATCH + // No cache for MATCH + make_join_readinfo(&join, + (select_options & (SELECT_DESCRIBE | + SELECT_NO_JOIN_CACHE)) | + (ftfuncs.elements ? SELECT_NO_JOIN_CACHE : 0)); /* Need to tell Innobase that to play it safe, it should fetch all columns of the tables: this is because MySQL @@ -508,7 +547,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, for (uint i_h = join.const_tables; i_h < join.tables; i_h++) { TABLE* table_h = join.join_tab[i_h].table; - if (table_h->db_type == DB_TYPE_INNOBASE) + if (table_h->db_type == DB_TYPE_INNODB) table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); } } @@ -532,7 +571,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, if (!(select_options & SELECT_BIG_RESULT) && ((group && join.const_tables != join.tables && !test_if_skip_sort_order(&join.join_tab[join.const_tables], group, - HA_POS_ERROR)) || + thd->select_limit,0)) || select_distinct) && join.tmp_table_param.quick_group && !procedure) { @@ -546,7 +585,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, if (order && (join.const_tables == join.tables || test_if_skip_sort_order(&join.join_tab[join.const_tables], order, - (group ? HA_POS_ERROR : thd->select_limit)))) + (join.const_tables != join.tables - 1 || + (join.select_options & OPTION_FOUND_ROWS)) ? + HA_POS_ERROR : thd->select_limit,0))) order=0; select_describe(&join,need_tmp, (order != 0 && @@ -559,7 +600,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, /* Perform FULLTEXT search before all regular searches */ if (ftfuncs.elements) { - List_iterator<Item_func_match> li(ftfuncs); + List_iterator_fast<Item_func_match> li(ftfuncs); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); thd->proc_info="FULLTEXT searching"; @@ -582,7 +623,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, group : (ORDER*) 0), group ? 0 : select_distinct, group && simple_group, - order == 0, + (order == 0 || skip_sort_order) && + !(join.select_options & OPTION_FOUND_ROWS), join.select_options))) goto err; /* purecov: inspected */ @@ -632,6 +674,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, break; join_tab->not_used_in_distinct=1; } while (join_tab-- != join.join_tab); + /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ + if (order && skip_sort_order) + { + (void) test_if_skip_sort_order(&join.join_tab[join.const_tables], + order, thd->select_limit,0); + order=0; + } } /* Copy data to the temporary table */ @@ -770,13 +819,34 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, /* If we have already done the group, add HAVING to sorted table */ if (having && ! group && ! join.sort_and_group) { - if (fix_having(&join,&having)) - goto err; + having->update_used_tables(); // Some tables may have been const + JOIN_TAB *table=&join.join_tab[join.const_tables]; + table_map used_tables= join.const_table_map | table->table->map; + + Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables); + if (sort_table_cond) + { + if (!table->select) + if (!(table->select=new SQL_SELECT)) + goto err; + if (!table->select->cond) + table->select->cond=sort_table_cond; + else // This should never happen + if (!(table->select->cond=new Item_cond_and(table->select->cond, + sort_table_cond))) + goto err; + table->select_cond=table->select->cond; + DBUG_EXECUTE("where",print_where(table->select->cond, + "select and having");); + having=make_cond_for_table(having,~ (table_map) 0,~used_tables); + DBUG_EXECUTE("where",print_where(conds,"having after sort");); + } } if (create_sort_index(&join.join_tab[join.const_tables], group ? group : order, (having || group || - join.const_tables != join.tables - 1) ? + join.const_tables != join.tables - 1 || + (join.select_options & OPTION_FOUND_ROWS)) ? HA_POS_ERROR : thd->select_limit)) goto err; /* purecov: inspected */ } @@ -785,7 +855,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, error=do_select(&join,&fields,NULL,procedure); err: - thd->examined_row_count=join.examined_rows; + thd->limit_found_rows = join.send_records; + thd->examined_row_count = join.examined_rows; thd->proc_info="end"; join.lock=0; // It's faster to unlock later join_free(&join); @@ -806,7 +877,7 @@ err: *****************************************************************************/ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, - key_map keys) + key_map keys,ha_rows limit) { int error; DBUG_ENTER("get_quick_record_count"); @@ -814,7 +885,7 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, { select->head=table; table->reginfo.impossible_range=0; - if ((error=select->test_quick_select(keys,(table_map) 0,HA_POS_ERROR)) + if ((error=select->test_quick_select(keys,(table_map) 0,limit)) == 1) DBUG_RETURN(select->quick->records); if (error == -1) @@ -1026,7 +1097,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, s->read_time=(ha_rows) s->table->file->scan_time(); /* Set a max range of how many seeks we can expect when using keys */ - s->worst_seeks= (double) (s->read_time*2); + /* This was (s->read_time*5), but this was too low with small rows */ + s->worst_seeks= (double) s->found_records / 5; if (s->worst_seeks < 2.0) // Fix for small tables s->worst_seeks=2.0; @@ -1039,7 +1111,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, select=make_select(s->table,const_table_map, 0, and_conds(conds,s->on_expr),&error); - records=get_quick_record_count(select,s->table, s->const_keys); + records=get_quick_record_count(select,s->table, s->const_keys, + join->row_limit); s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; @@ -1224,7 +1297,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, { if (cond->type() == Item_func::COND_ITEM) { - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); KEY_FIELD *org_key_fields= *key_fields; if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) @@ -1392,7 +1465,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, } else if (cond->type() == Item::COND_ITEM) { - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { @@ -1728,7 +1801,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { /* we can use only index tree */ uint keys_per_block= table->file->block_size/2/ - keyinfo->key_length+1; + (keyinfo->key_length+table->file->ref_length)+1; tmp=(record_count*(records+keys_per_block-1)/ keys_per_block); } @@ -1798,7 +1871,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { /* we can use only index tree */ uint keys_per_block= table->file->block_size/2/ - keyinfo->key_length+1; + (keyinfo->key_length+table->file->ref_length)+1; tmp=record_count*(tmp+keys_per_block-1)/keys_per_block; } else @@ -2203,13 +2276,15 @@ make_simple_join(JOIN *join,TABLE *tmp_table) join->tables=1; join->const_tables=0; join->const_table_map=0; - join->tmp_table_param.copy_field_count=join->tmp_table_param.field_count= - join->tmp_table_param.sum_func_count= join->tmp_table_param.func_count=0; - join->tmp_table_param.copy_field=0; + join->tmp_table_param.field_count= join->tmp_table_param.sum_func_count= + join->tmp_table_param.func_count=0; + join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0; join->first_record=join->sort_and_group=0; join->sum_funcs=0; join->send_records=(ha_rows) 0; join->group=0; + join->do_send_rows = 1; + join->row_limit=HA_POS_ERROR; join_tab->cache.buff=0; /* No cacheing */ join_tab->table=tmp_table; @@ -2311,15 +2386,19 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ if ((tab->keys & ~ tab->const_keys && i > 0) || - tab->const_keys && i == join->const_tables && - join->thd->select_limit < join->best_positions[i].records_read) + (tab->const_keys && i == join->const_tables && + join->thd->select_limit < join->best_positions[i].records_read && + !(join->select_options & OPTION_FOUND_ROWS))) { /* Join with outer join condition */ COND *orig_cond=sel->cond; sel->cond=and_conds(sel->cond,tab->on_expr); if (sel->test_quick_select(tab->keys, used_tables & ~ current_map, - join->thd->select_limit) < 0) + (join->select_options & + OPTION_FOUND_ROWS ? + HA_POS_ERROR : + join->thd->select_limit)) < 0) DBUG_RETURN(1); // Impossible range sel->cond=orig_cond; } @@ -2440,7 +2519,7 @@ make_join_readinfo(JOIN *join,uint options) ** if previous table use cache */ table->status=STATUS_NO_RECORD; - if (i != join->const_tables && (options & SELECT_USE_CACHE) && + if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && tab->use_quick != 2 && !tab->on_expr) { if ((options & SELECT_DESCRIBE) || @@ -2453,7 +2532,7 @@ make_join_readinfo(JOIN *join,uint options) /* These init changes read_record */ if (tab->use_quick == 2) { - join->thd->lex.options|=QUERY_NO_GOOD_INDEX_USED; + join->thd->lex.select_lex.options|=QUERY_NO_GOOD_INDEX_USED; tab->read_first_record= join_init_quick_read_record; statistic_increment(select_range_check_count, &LOCK_status); } @@ -2468,7 +2547,7 @@ make_join_readinfo(JOIN *join,uint options) } else { - join->thd->lex.options|=QUERY_NO_INDEX_USED; + join->thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; statistic_increment(select_scan_count, &LOCK_status); } } @@ -2480,7 +2559,7 @@ make_join_readinfo(JOIN *join,uint options) } else { - join->thd->lex.options|=QUERY_NO_INDEX_USED; + join->thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; statistic_increment(select_full_join_count, &LOCK_status); } } @@ -2548,7 +2627,8 @@ join_free(JOIN *join) } // We are not using tables anymore // Unlock all tables. We may be in an INSERT .... SELECT statement. - if (join->lock && join->thd->lock) + if (join->lock && join->thd->lock && + !(join->select_options & SELECT_NO_UNLOCK)) { mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock join->lock=0; @@ -2907,7 +2987,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, { bool and_level= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); Item *item; I_List<COND_CMP> save; while ((item=li++)) @@ -2935,7 +3015,9 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, Item_func_eq *func=(Item_func_eq*) cond; bool left_const= func->arguments()[0]->const_item(); bool right_const=func->arguments()[1]->const_item(); - if (!(left_const && right_const)) + if (!(left_const && right_const) && + (func->arguments()[0]->result_type() == + (func->arguments()[1]->result_type()))) { if (right_const) { @@ -3134,7 +3216,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) { bool and_level= (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC); - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list()); Item *item; while ((item=li++)) { @@ -3299,13 +3381,14 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, uint select_options) + bool allow_distinct_limit, ulong select_options) { TABLE *table; uint i,field_count,reclength,null_count,null_pack_length, hidden_null_count, hidden_null_pack_length, hidden_field_count, blob_count,group_null_items; bool using_unique_constraint=0; + bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS); char *tmpname,path[FN_REFLEN]; byte *pos,*group_buff; uchar *null_flags; @@ -3396,24 +3479,27 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, reclength=blob_count=null_count=hidden_null_count=group_null_items=0; param->using_indirect_summary_function=0; - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Item *item; Field **tmp_from_field=from_field; while ((item=li++)) { Item::Type type=item->type(); - if (item->with_sum_func && type != Item::SUM_FUNC_ITEM) + if (not_all_columns) { - /* - Mark that the we have ignored an item that refers to a summary - function. We need to know this if someone is going to use - DISTINCT on the result. - */ - param->using_indirect_summary_function=1; - continue; + if (item->with_sum_func && type != Item::SUM_FUNC_ITEM) + { + /* + Mark that the we have ignored an item that refers to a summary + function. We need to know this if someone is going to use + DISTINCT on the result. + */ + param->using_indirect_summary_function=1; + continue; + } + if (item->const_item()) // We don't have to store this + continue; } - if (item->const_item()) // We don't have to store this - continue; if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields) { /* Can't calc group yet */ ((Item_sum*) item)->result_field=0; @@ -3424,7 +3510,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, { Field *new_field= create_tmp_field(table,arg,arg->type(),©_func,tmp_from_field, - group != 0,1); + group != 0,not_all_columns); if (!new_field) goto err; // Should be OOM tmp_from_field++; @@ -3441,7 +3527,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, else { Field *new_field=create_tmp_field(table,item,type,©_func, - tmp_from_field, group != 0,1); + tmp_from_field, group != 0, + not_all_columns); if (!new_field) { if (thd->fatal_error) @@ -3578,7 +3665,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, null_count=(null_count+7) & ~7; // move to next byte } - param->copy_field_count=(uint) (copy - param->copy_field); + param->copy_field_end=copy; param->recinfo=recinfo; store_record(table,2); // Make empty default record @@ -3741,7 +3828,7 @@ static bool open_tmp_table(TABLE *table) static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, - uint options) + ulong options) { int error; MI_KEYDEF keydef; @@ -3902,12 +3989,18 @@ bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error, thd->proc_info="converting HEAP to MyISAM"; if (create_myisam_tmp_table(&new_table,param, - thd->lex.options | thd->options)) + thd->lex.select_lex.options | thd->options)) goto err2; if (open_tmp_table(&new_table)) goto err1; table->file->index_end(); table->file->rnd_init(); + if (table->no_rows) + { + new_table.file->extra(HA_EXTRA_NO_ROWS); + new_table.no_rows=1; + } + /* copy all old rows */ while (!table->file->rnd_next(new_table.record[1])) { @@ -4615,14 +4708,23 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int error; if (join->having && join->having->val_int() == 0) DBUG_RETURN(0); // Didn't match having + error=0; if (join->procedure) error=join->procedure->send_row(*join->fields); - else + else if (join->do_send_rows) error=join->result->send_data(*join->fields); if (error) DBUG_RETURN(-1); /* purecov: inspected */ - if (++join->send_records >= join->thd->select_limit) + if (++join->send_records >= join->thd->select_limit && join->do_send_rows) + { + if (join->select_options & OPTION_FOUND_ROWS) + { + join->do_send_rows=0; + join->thd->select_limit = HA_POS_ERROR; + DBUG_RETURN(0); + } DBUG_RETURN(-3); // Abort nicely + } } else { @@ -4653,9 +4755,10 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int error; if (join->procedure) { + error=0; if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having - else + else if (join->do_send_rows) error=join->procedure->send_row(*join->fields) ? 1 : 0; if (end_of_records && join->procedure->end_of_records()) error= 1; // Fatal error @@ -4677,8 +4780,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(-1); /* purecov: inspected */ if (end_of_records) DBUG_RETURN(0); - if (!error && ++join->send_records >= join->thd->select_limit) - DBUG_RETURN(-3); /* Abort nicely */ + if (!error && ++join->send_records >= join->thd->select_limit && + join->do_send_rows) + { + if (!(join->select_options & OPTION_FOUND_ROWS)) + DBUG_RETURN(-3); // Abort nicely + join->do_send_rows=0; + join->thd->select_limit = HA_POS_ERROR; + } } } else @@ -4749,8 +4858,15 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (create_myisam_from_heap(table, &join->tmp_table_param, error,1)) DBUG_RETURN(1); // Not a table_is_full error table->uniques=0; // To ensure rows are the same - if (++join->send_records >= join->tmp_table_param.end_write_records) + } + if (++join->send_records >= join->tmp_table_param.end_write_records & + join->do_send_rows) + { + if (!(join->select_options & OPTION_FOUND_ROWS)) DBUG_RETURN(-3); + join->do_send_rows=0; + join->thd->select_limit = HA_POS_ERROR; + DBUG_RETURN(0); } } } @@ -5085,9 +5201,11 @@ part_of_refkey(TABLE *table,Field *field) ** Returns: 1 if key is ok. ** 0 if key can't be used ** -1 if reverse key can be used +** used_key_parts is set to key parts used if length != 0 *****************************************************************************/ -static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx) +static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, + uint *used_key_parts) { KEY_PART_INFO *key_part,*key_part_end; key_part=table->key_info[idx].key_part; @@ -5119,6 +5237,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx) reverse=flag; // Remember if reverse key_part++; } + *used_key_parts= (uint) (key_part - table->key_info[idx].key_part); return reverse; } @@ -5151,7 +5270,8 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys) /* Return 1 if we don't have to do file sorting */ static bool -test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) +test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, + bool no_changes) { int ref_key; TABLE *table=tab->table; @@ -5179,10 +5299,41 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) if (ref_key >= 0) { + int order_direction; + uint used_key_parts; /* Check if we get the rows in requested sorted order by using the key */ if ((usable_keys & ((key_map) 1 << ref_key)) && - test_if_order_by_key(order,table,ref_key) == 1) + (order_direction = test_if_order_by_key(order,table,ref_key, + &used_key_parts))) + { + if (order_direction == -1) + { + if (select && select->quick) + { + // ORDER BY ref_key DESC + QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick, + used_key_parts); + if (!tmp || tmp->error) + { + delete tmp; + DBUG_RETURN(0); // Reverse sort not supported + } + select->quick=tmp; + DBUG_RETURN(1); + } + if (tab->ref.key_parts < used_key_parts) + { + /* + SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC + TODO: + Add a new traversal function to read last matching row and + traverse backwards. + */ + DBUG_RETURN(0); + } + } DBUG_RETURN(1); /* No need to sort */ + } } else { @@ -5201,16 +5352,20 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) for (nr=0; keys ; keys>>=1, nr++) { + uint not_used; if (keys & 1) { int flag; - if ((flag=test_if_order_by_key(order,table,nr))) + if ((flag=test_if_order_by_key(order, table, nr, ¬_used))) { - tab->index=nr; - tab->read_first_record= (flag > 0 ? join_init_read_first_with_key: - join_init_read_last_with_key); - table->file->index_init(nr); - tab->type=JT_NEXT; // Read with index_first(), index_next() + if (!no_changes) + { + tab->index=nr; + tab->read_first_record= (flag > 0 ? join_init_read_first_with_key: + join_init_read_last_with_key); + table->file->index_init(nr); + tab->type=JT_NEXT; // Read with index_first(), index_next() + } DBUG_RETURN(1); } } @@ -5229,7 +5384,7 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) SQL_SELECT *select=tab->select; DBUG_ENTER("create_sort_index"); - if (test_if_skip_sort_order(tab,order,select_limit)) + if (test_if_skip_sort_order(tab,order,select_limit,0)) DBUG_RETURN(0); if (!(sortorder=make_unireg_sortorder(order,&length))) goto err; /* purecov: inspected */ @@ -5262,7 +5417,9 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) goto err; } } - table->found_records=filesort(&table,sortorder,length, + if (table->tmp_table) + table->file->info(HA_STATUS_VARIABLE); // Get record count + table->found_records=filesort(table,sortorder,length, select, 0L, select_limit, &examined_rows); delete select; // filesort did select tab->select=0; @@ -6305,7 +6462,7 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields) goto err; } } - param->copy_field_count= (uint) (copy - param->copy_field); + param->copy_field_end= copy; DBUG_RETURN(0); err: @@ -6323,17 +6480,16 @@ void copy_fields(TMP_TABLE_PARAM *param) { Copy_field *ptr=param->copy_field; - Copy_field *end=ptr+param->copy_field_count; + Copy_field *end=param->copy_field_end; for ( ; ptr != end; ptr++) (*ptr->do_copy)(ptr); - List_iterator<Item> it(param->copy_funcs); + List_iterator_fast<Item> &it=param->copy_funcs_it; + it.rewind(); Item_copy_string *item; while ((item = (Item_copy_string*) it++)) - { item->copy(); - } } @@ -6599,24 +6755,26 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, DBUG_ENTER("select_describe"); /* Don't log this into the slow query log */ - join->thd->lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); - field_list.push_back(new Item_empty_string("table",NAME_LEN)); - field_list.push_back(new Item_empty_string("type",10)); - field_list.push_back(item=new Item_empty_string("possible_keys", + join->thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); + if (join->thd->lex.select == &join->thd->lex.select_lex) + { + field_list.push_back(new Item_empty_string("table",NAME_LEN)); + field_list.push_back(new Item_empty_string("type",10)); + field_list.push_back(item=new Item_empty_string("possible_keys", NAME_LEN*MAX_KEY)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); - item->maybe_null=1; - field_list.push_back(item=new Item_int("key_len",0,3)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("ref", - NAME_LEN*MAX_REF_PARTS)); - item->maybe_null=1; - field_list.push_back(new Item_real("rows",0.0,0,10)); - field_list.push_back(new Item_empty_string("Extra",255)); - if (send_fields(thd,field_list,1)) - return; /* purecov: inspected */ - + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); + item->maybe_null=1; + field_list.push_back(item=new Item_int("key_len",0,3)); + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("ref", + NAME_LEN*MAX_REF_PARTS)); + item->maybe_null=1; + field_list.push_back(new Item_real("rows",0.0,0,10)); + field_list.push_back(new Item_empty_string("Extra",255)); + if (send_fields(thd,field_list,1)) + return; + } char buff[512],*buff_ptr; String tmp(buff,sizeof(buff)),*packet= &thd->packet; table_map used_tables=0; @@ -6747,7 +6905,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, // For next iteration used_tables|=table->map; } - send_eof(&thd->net); + if (!join->thd->lex.select->next) + send_eof(&thd->net); DBUG_VOID_RETURN; } @@ -6758,7 +6917,7 @@ static void describe_info(THD *thd, const char *info) String *packet= &thd->packet; /* Don't log this into the slow query log */ - thd->lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); + thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); field_list.push_back(new Item_empty_string("Comment",80)); if (send_fields(thd,field_list,1)) return; /* purecov: inspected */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 1bf7d7863eb..4fcffae31d2 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -118,19 +118,21 @@ typedef struct st_position { /* Used in find_best */ class TMP_TABLE_PARAM { public: List<Item> copy_funcs; - Copy_field *copy_field; + List_iterator_fast<Item> copy_funcs_it; + Copy_field *copy_field, *copy_field_end; byte *group_buff; Item_result_field **funcs; MI_COLUMNDEF *recinfo,*start_recinfo; KEY *keyinfo; ha_rows end_write_records; - uint copy_field_count,field_count,sum_func_count,func_count; + uint field_count,sum_func_count,func_count; uint hidden_field_count; uint group_parts,group_length; uint quick_group; bool using_indirect_summary_function; - TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0) + TMP_TABLE_PARAM() + :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0), group_length(0) {} ~TMP_TABLE_PARAM() { @@ -154,6 +156,7 @@ class JOIN { uint tables,const_tables; uint send_group_parts; bool sort_and_group,first_record,full_join,group, no_field_update; + bool do_send_rows; table_map const_table_map,outer_join; ha_rows send_records,found_records,examined_rows,row_limit; POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; @@ -183,7 +186,7 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, uint select_options); + bool allow_distinct_limit, ulong select_options); void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, bool reset_with_sum_func); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5869feefdc3..7806bef7163 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -17,6 +17,7 @@ /* Function with list databases, tables or fields */ +#include "global.h" #include "mysql_priv.h" #include "sql_select.h" // For select_describe #include "sql_acl.h" @@ -45,6 +46,8 @@ store_create_info(THD *thd, TABLE *table, String *packet); static void append_identifier(THD *thd, String *packet, const char *name); +extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; + /**************************************************************************** ** Send list of databases ** A database is a directory in the mysql_data_home directory @@ -72,7 +75,7 @@ mysqld_show_dbs(THD *thd,const char *wild) DBUG_RETURN(1); if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1)) DBUG_RETURN(1); - List_iterator<char> it(files); + List_iterator_fast<char> it(files); while ((file_name=it++)) { if (!opt_safe_show_db || thd->master_access || @@ -81,7 +84,7 @@ mysqld_show_dbs(THD *thd,const char *wild) (grant_option && !check_grant_db(thd, file_name))) { thd->packet.length(0); - net_store_data(&thd->packet,file_name); + net_store_data(&thd->packet, thd->convert_set, file_name); if (my_net_write(&thd->net, (char*) thd->packet.ptr(), thd->packet.length())) DBUG_RETURN(-1); @@ -95,34 +98,31 @@ mysqld_show_dbs(THD *thd,const char *wild) ** List all open tables in a database ***************************************************************************/ -int mysqld_show_open_tables(THD *thd,const char *db,const char *wild) +int mysqld_show_open_tables(THD *thd,const char *wild) { - Item_string *field=new Item_string("",0); List<Item> field_list; - char *end,*table_name; - List<char> tables; + OPEN_TABLE_LIST *open_list; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_show_open_tables"); - field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0)); - end=strxmov(field->name,"Open_tables_in_",db,NullS); - if (wild && wild[0]) - strxmov(end," (",wild,")",NullS); - field->max_length=NAME_LEN; - field_list.push_back(field); - field_list.push_back(new Item_empty_string("Comment",80)); + field_list.push_back(new Item_empty_string("Database",NAME_LEN)); + field_list.push_back(new Item_empty_string("Table",NAME_LEN)); + field_list.push_back(new Item_int("In_use",0, 4)); + field_list.push_back(new Item_int("Name_locked",0, 4)); if (send_fields(thd,field_list,1)) DBUG_RETURN(1); - if (list_open_tables(thd,&tables,db,wild)) + if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error) DBUG_RETURN(-1); - List_iterator<char> it(tables); - while ((table_name=it++)) + for ( ; open_list ; open_list=open_list->next) { thd->packet.length(0); - net_store_data(&thd->packet,table_name); - net_store_data(&thd->packet,query_table_status(thd,db,table_name)); + net_store_data(&thd->packet,convert, open_list->db); + net_store_data(&thd->packet,convert, open_list->table); + net_store_data(&thd->packet,open_list->in_use); + net_store_data(&thd->packet,open_list->locked); if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) DBUG_RETURN(-1); } @@ -157,11 +157,11 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) DBUG_RETURN(1); if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); - List_iterator<char> it(files); + List_iterator_fast<char> it(files); while ((file_name=it++)) { thd->packet.length(0); - net_store_data(&thd->packet,file_name); + net_store_data(&thd->packet, thd->convert_set, file_name); if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) DBUG_RETURN(-1); } @@ -257,6 +257,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) char *file_name; TABLE *table; String *packet= &thd->packet; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_extend_show_tables"); (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -296,20 +297,20 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); - List_iterator<char> it(files); + List_iterator_fast<char> it(files); while ((file_name=it++)) { TABLE_LIST table_list; bzero((char*) &table_list,sizeof(table_list)); packet->length(0); - net_store_data(packet,file_name); + net_store_data(packet,convert, file_name); table_list.db=(char*) db; table_list.real_name=table_list.name=file_name; if (!(table = open_ltable(thd, &table_list, TL_READ))) { for (uint i=0 ; i < field_list.elements ; i++) net_store_null(packet); - net_store_data(packet,thd->net.last_error); + net_store_data(packet,convert, thd->net.last_error); thd->net.last_error[0]=0; } else @@ -317,8 +318,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) struct tm tm_tmp; handler *file=table->file; file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); - net_store_data(packet, file->table_type()); - net_store_data(packet, + net_store_data(packet, convert, file->table_type()); + net_store_data(packet, convert, (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? "Dynamic" : (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) @@ -399,7 +400,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); ptr=strmov(ptr,buff); } - net_store_data(packet, option_buff+1, + net_store_data(packet, convert, option_buff+1, (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); } { @@ -431,6 +432,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, TABLE *table; handler *file; char tmp[MAX_FIELD_WIDTH]; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_show_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -485,18 +487,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, bool null_default_value=0; packet->length(0); - net_store_data(packet,field->field_name); + net_store_data(packet,convert,field->field_name); field->sql_type(type); - net_store_data(packet,type.ptr(),type.length()); + net_store_data(packet,convert,type.ptr(),type.length()); pos=(byte*) ((flags & NOT_NULL_FLAG) && field->type() != FIELD_TYPE_TIMESTAMP ? "" : "YES"); - net_store_data(packet,(const char*) pos); + net_store_data(packet,convert,(const char*) pos); pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); - net_store_data(packet,(char*) pos); + net_store_data(packet,convert,(char*) pos); if (field->type() == FIELD_TYPE_TIMESTAMP || field->unireg_check == Field::NEXT_NUMBER) @@ -505,17 +507,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, { // Not null by default type.set(tmp,sizeof(tmp)); field->val_str(&type,&type); - net_store_data(packet,type.ptr(),type.length()); + net_store_data(packet,convert,type.ptr(),type.length()); } else if (field->maybe_null() || null_default_value) net_store_null(packet); // Null as default else - net_store_data(packet,tmp,0); + net_store_data(packet,convert,tmp,0); char *end=tmp; if (field->unireg_check == Field::NEXT_NUMBER) end=strmov(tmp,"auto_increment"); - net_store_data(packet,tmp,(uint) (end-tmp)); + net_store_data(packet,convert,tmp,(uint) (end-tmp)); if (verbose) { @@ -530,7 +532,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, end=strmov(end,grant_types.type_names[bitnr]); } } - net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); + net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); } if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(1); @@ -545,6 +547,7 @@ int mysqld_show_create(THD *thd, TABLE_LIST *table_list) { TABLE *table; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -566,7 +569,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) String *packet = &thd->packet; { packet->length(0); - net_store_data(packet, table->table_name); + net_store_data(packet,convert, table->table_name); // a hack - we need to reserve some space for the length before // we know what it is - let's assume that the length of create table // statement will fit into 3 bytes ( 16 MB max :-) ) @@ -623,6 +626,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) { TABLE *table; char buff[256]; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_show_keys"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -664,16 +668,18 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { packet->length(0); - net_store_data(packet,table->table_name); - net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1); - net_store_data(packet,key_info->name); + net_store_data(packet,convert,table->table_name); + net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1); + net_store_data(packet,convert,key_info->name); end=int10_to_str((long) (j+1),(char*) buff,10); - net_store_data(packet,buff,(uint) (end-buff)); - net_store_data(packet,key_part->field ? key_part->field->field_name : + net_store_data(packet,convert,buff,(uint) (end-buff)); + net_store_data(packet,convert, + key_part->field ? key_part->field->field_name : "?unknown field?"); if (table->file->option_flag() & HA_READ_ORDER) - net_store_data(packet,((key_part->key_part_flag & HA_REVERSE_SORT) - ? "D" : "A"), 1); + net_store_data(packet,convert, + ((key_part->key_part_flag & HA_REVERSE_SORT) ? + "D" : "A"), 1); else net_store_null(packet); /* purecov: inspected */ KEY *key=table->key_info+i; @@ -681,7 +687,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) { ulong records=(table->file->records / key->rec_per_key[j]); end=int10_to_str((long) records, buff, 10); - net_store_data(packet,buff,(uint) (end-buff)); + net_store_data(packet,convert,buff,(uint) (end-buff)); } else net_store_null(packet); @@ -690,12 +696,13 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) table->field[key_part->fieldnr-1]->key_length()) { end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */ - net_store_data(packet,buff,(uint) (end-buff)); /* purecov: inspected */ + net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */ } else net_store_null(packet); net_store_null(packet); // No pack_information yet - net_store_data(packet,key_info->flags & HA_FULLTEXT ? "FULLTEXT":""); + net_store_data(packet,convert, + key_info->flags & HA_FULLTEXT ? "FULLTEXT":""); if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(1); /* purecov: inspected */ } @@ -740,15 +747,18 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) int mysqld_dump_create_info(THD *thd, TABLE *table, int fd) { + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_dump_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); + String* packet = &thd->packet; packet->length(0); - - if(store_create_info(thd,table,packet)) + if (store_create_info(thd,table,packet)) DBUG_RETURN(-1); - if(fd < 0) + if (convert) + convert->convert((char*) packet->ptr(), packet->length()); + if (fd < 0) { if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) DBUG_RETURN(-1); @@ -966,6 +976,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) List<Item> field_list; I_List<thread_info> thread_infos; ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_list_processes"); field_list.push_back(new Item_int("Id",0,7)); @@ -995,10 +1006,13 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thread_info *thd_info=new thread_info; thd_info->thread_id=tmp->thread_id; - thd_info->user=thd->strdup(tmp->user ? tmp->user : (tmp->system_thread ? - "system user" : "unauthenticated user")); - thd_info->host=thd->strdup(tmp->host ? tmp->host : (tmp->ip ? tmp->ip : - (tmp->system_thread ? "none" : "connecting host"))); + thd_info->user=thd->strdup(tmp->user ? tmp->user : + (tmp->system_thread ? + "system user" : "unauthenticated user")); + thd_info->host=thd->strdup(tmp->host ? tmp->host : + (tmp->ip ? tmp->ip : + (tmp->system_thread ? "none" : + "connecting host"))); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; @@ -1049,28 +1063,28 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) char buff[20],*end; packet->length(0); end=int10_to_str((long) thd_info->thread_id, buff,10); - net_store_data(packet,buff,(uint) (end-buff)); - net_store_data(packet,thd_info->user); - net_store_data(packet,thd_info->host); + net_store_data(packet,convert,buff,(uint) (end-buff)); + net_store_data(packet,convert,thd_info->user); + net_store_data(packet,convert,thd_info->host); if (thd_info->db) - net_store_data(packet,thd_info->db); + net_store_data(packet,convert,thd_info->db); else net_store_null(packet); if (thd_info->proc_info) - net_store_data(packet,thd_info->proc_info); + net_store_data(packet,convert,thd_info->proc_info); else - net_store_data(packet,command_name[thd_info->command]); + net_store_data(packet,convert,command_name[thd_info->command]); if (thd_info->start_time) - net_store_data(packet,(uint32) - (time((time_t*) 0) - thd_info->start_time)); + net_store_data(packet, + (uint32) (time((time_t*) 0) - thd_info->start_time)); else net_store_null(packet); if (thd_info->state_info) - net_store_data(packet,thd_info->state_info); + net_store_data(packet,convert,thd_info->state_info); else net_store_null(packet); if (thd_info->query) - net_store_data(packet,thd_info->query); + net_store_data(packet,convert,thd_info->query); else net_store_null(packet); if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) @@ -1092,6 +1106,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) char buff[8192]; String packet2(buff,sizeof(buff)); List<Item> field_list; + CONVERT *convert=thd->convert_set; DBUG_ENTER("mysqld_show"); field_list.push_back(new Item_empty_string("Variable_name",30)); field_list.push_back(new Item_empty_string("Value",256)); @@ -1105,7 +1120,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) if (!(wild && wild[0] && wild_compare(variables[i].name,wild))) { packet2.length(0); - net_store_data(&packet2,variables[i].name); + net_store_data(&packet2,convert,variables[i].name); switch (variables[i].type){ case SHOW_LONG: case SHOW_LONG_CONST: @@ -1132,7 +1147,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) break; } case SHOW_CHAR: - net_store_data(&packet2,variables[i].value); + net_store_data(&packet2,convert, variables[i].value); break; case SHOW_STARTTIME: net_store_data(&packet2,(uint32) (thd->query_start() - start_time)); @@ -1146,9 +1161,95 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) case SHOW_CHAR_PTR: { char *value= *(char**) variables[i].value; - net_store_data(&packet2,value ? value : ""); + net_store_data(&packet2,convert, value ? value : ""); break; } +#ifdef HAVE_OPENSSL + /* First group - functions relying on CTX */ + case SHOW_SSL_CTX_SESS_ACCEPT: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_SESS_ACCEPT_GOOD: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_SESS_CB_HITS: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_SESS_NUMBER: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE: + net_store_data(&packet2,(uint32) + SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_GET_VERIFY_MODE: + net_store_data(&packet2,(uint32) + SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_GET_VERIFY_DEPTH: + net_store_data(&packet2,(uint32) + SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)); + break; + case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE: + switch(SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_)) + { + case SSL_SESS_CACHE_OFF: + net_store_data(&packet2,"OFF" ); + break; + case SSL_SESS_CACHE_CLIENT: + net_store_data(&packet2,"CLIENT" ); + break; + case SSL_SESS_CACHE_SERVER: + net_store_data(&packet2,"SERVER" ); + break; + case SSL_SESS_CACHE_BOTH: + net_store_data(&packet2,"BOTH" ); + break; + case SSL_SESS_CACHE_NO_AUTO_CLEAR: + net_store_data(&packet2,"NO_AUTO_CLEAR" ); + break; + case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: + net_store_data(&packet2,"NO_INTERNAL_LOOKUP" ); + break; + default: + net_store_data(&packet2,"Unknown"); + break; + } + break; + /* First group - functions relying on SSL */ + case SHOW_SSL_GET_VERSION: + net_store_data(&packet2, thd->net.vio->ssl_ ? + SSL_get_version(thd->net.vio->ssl_) : ""); + break; + case SHOW_SSL_SESSION_REUSED: + net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? + SSL_session_reused(thd->net.vio->ssl_) : 0)); + break; + case SHOW_SSL_GET_DEFAULT_TIMEOUT: + net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? + SSL_get_default_timeout(thd->net.vio->ssl_):0)); + break; + case SHOW_SSL_GET_VERIFY_MODE: + net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? + SSL_get_verify_mode(thd->net.vio->ssl_):0)); + break; + case SHOW_SSL_GET_VERIFY_DEPTH: + net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? + SSL_get_verify_depth(thd->net.vio->ssl_):0)); + break; + case SHOW_SSL_GET_CIPHER: + net_store_data(&packet2, thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : ""); + break; + +#endif /* HAVE_OPENSSL */ } if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) goto err; /* purecov: inspected */ @@ -1166,6 +1267,6 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables) } #ifdef __GNUC__ -template class List_iterator<char>; +template class List_iterator_fast<char>; template class List<char>; #endif diff --git a/sql/sql_sort.h b/sql/sql_sort.h new file mode 100644 index 00000000000..62c5f1cb164 --- /dev/null +++ b/sql/sql_sort.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2000 MySQL AB + + 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 */ + +/* Defines used by filesort and uniques */ + +#define MERGEBUFF 7 +#define MERGEBUFF2 15 + +typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */ + my_off_t file_pos; /* Where we are in the sort file */ + uchar *base,*key; /* key pointers */ + ha_rows count; /* Number of rows in table */ + ulong mem_count; /* numbers of keys in memory */ + ulong max_keys; /* Max keys in buffert */ +} BUFFPEK; + + +typedef struct st_sort_param { + uint sort_length; /* Length of sort columns */ + uint keys; /* Max keys / buffert */ + uint ref_length; /* Length of record ref. */ + ha_rows max_rows,examined_rows; + TABLE *sort_form; /* For quicker make_sortkey */ + SORT_FIELD *local_sortorder; + SORT_FIELD *end; + uchar *unique_buff; + bool not_killable; +#ifdef USE_STRCOLL + char* tmp_buffer; +#endif +} SORTPARAM; + + +int merge_many_buff(SORTPARAM *param, uchar *sort_buffer, + BUFFPEK *buffpek, + uint *maxbuffer, IO_CACHE *t_file); +uint read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek, + uint sort_length); +int merge_buffers(SORTPARAM *param,IO_CACHE *from_file, + IO_CACHE *to_file, uchar *sort_buffer, + BUFFPEK *lastbuff,BUFFPEK *Fb, + BUFFPEK *Tb,int flag); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4735e8a08ec..ad9bf532268 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -43,12 +43,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) { - char path[FN_REFLEN]; - String wrong_tables; - bool some_tables_deleted=0; - uint error; - db_type table_type; - TABLE_LIST *table; + int error; DBUG_ENTER("mysql_rm_table"); /* mark for close and remove all cached entries */ @@ -72,7 +67,35 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) } } - + error=mysql_rm_table_part2(thd,tables,if_exists,0); + + err: + VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh + pthread_mutex_unlock(&LOCK_open); + + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + pthread_mutex_unlock(&thd->mysys_var->mutex); + + if (error) + DBUG_RETURN(-1); + send_ok(&thd->net); + DBUG_RETURN(0); +} + + +int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, + bool dont_log_query) +{ + TABLE_LIST *table; + char path[FN_REFLEN]; + String wrong_tables; + db_type table_type; + int error; + bool some_tables_deleted=0; + DBUG_ENTER("mysql_rm_table_part2"); + for (table=tables ; table ; table=table->next) { char *db=table->db ? table->db : thd->db; @@ -135,7 +158,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) wrong_tables.append(String(table->real_name)); } } - if (some_tables_deleted) + if (some_tables_deleted && !dont_log_query) { mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) @@ -146,24 +169,12 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) } error = 0; - err: - VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh - pthread_mutex_unlock(&LOCK_open); - - pthread_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - if (wrong_tables.length()) { my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr()); error=1; } - if(error) - DBUG_RETURN(-1); - send_ok(&thd->net); - DBUG_RETURN(0); + DBUG_RETURN(error); } @@ -667,7 +678,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ - List_iterator<Item> it(*items); + List_iterator_fast<Item> it(*items); Item *item; Field *tmp_field; tmp_table.db_create_options=0; @@ -835,21 +846,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table) sprintf(dst_path, "%s/%s/%s", mysql_real_data_home, db, table_name); - int lock_retcode; - pthread_mutex_lock(&LOCK_open); - if ((lock_retcode = lock_table_name(thd, table)) < 0) - { - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(-1); - } - - if (lock_retcode && wait_for_locked_table_names(thd, table)) - { - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); + if (lock_and_wait_for_table_name(thd,table)) DBUG_RETURN(-1); - } - pthread_mutex_unlock(&LOCK_open); if (my_copy(src_path, fn_format(dst_path, dst_path,"", @@ -860,25 +858,17 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table) DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed copying .frm file")); } - bool save_no_send_ok = thd->net.no_send_ok; - thd->net.no_send_ok = 1; - // generate table will try to send OK which messes up the output - // for the client - - if (generate_table(thd, table, 0)) + if (mysql_truncate(thd, table, 1)) { unlock_table_name(thd, table); - thd->net.no_send_ok = save_no_send_ok; DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed generating table from .frm file")); } - - thd->net.no_send_ok = save_no_send_ok; } - DBUG_RETURN(0); } + static int mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt, const char *operator_name, @@ -1108,12 +1098,15 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, List<Alter_column> &alter_list, ORDER *order, bool drop_primary, - enum enum_duplicates handle_duplicates) + enum enum_duplicates handle_duplicates, + enum enum_enable_or_disable keys_onoff, + bool simple_alter) { TABLE *table,*new_table; int error; char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN], - *table_name,*db; + *table_name,*db; + char index_file[FN_REFLEN], data_file[FN_REFLEN]; bool use_timestamp=0; ha_rows copied,deleted; ulonglong next_insert_id; @@ -1174,39 +1167,52 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (create_info->row_type == ROW_TYPE_DEFAULT) create_info->row_type=table->row_type; - /* Check if the user only wants to do a simple RENAME */ + /* In some simple cases we need not to recreate the table */ thd->proc_info="setup"; - if (new_name != table_name && - !fields.elements && !keys.elements && ! drop_list.elements && - !alter_list.elements && !drop_primary && - new_db_type == old_db_type && create_info->max_rows == 0 && - create_info->auto_increment_value == 0 && !table->tmp_table) + if (simple_alter) { - thd->proc_info="rename"; - VOID(pthread_mutex_lock(&LOCK_open)); - /* Then do a 'simple' rename of the table */ error=0; - if (!access(new_name_buff,F_OK)) - { - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name); - error= -1; - } - else + if (new_name != table_name) { - *fn_ext(new_name)=0; - close_cached_table(thd,table); - if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name)) - error= -1; + thd->proc_info="rename"; + VOID(pthread_mutex_lock(&LOCK_open)); + /* Then do a 'simple' rename of the table */ + error=0; + if (!access(new_name_buff,F_OK)) + { + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name); + error= -1; + } + else + { + *fn_ext(new_name)=0; + close_cached_table(thd,table); + if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name)) + error= -1; + } + if (!error && (error=ha_commit_rename(thd))) + { + my_error(ER_GET_ERRNO,MYF(0),error); + error=1; + } + + VOID(pthread_cond_broadcast(&COND_refresh)); + VOID(pthread_mutex_unlock(&LOCK_open)); } - if (!error && (error=ha_commit_rename(thd))) + if (!error) { - my_error(ER_GET_ERRNO,MYF(0),error); - error=1; + switch (keys_onoff) + { + case LEAVE_AS_IS: break; + case ENABLE: + error=table->file->activate_all_index(thd); + break; + case DISABLE: + table->file->deactivate_non_unique_index(HA_POS_ERROR); + break; + } } - - VOID(pthread_cond_broadcast(&COND_refresh)); - VOID(pthread_mutex_unlock(&LOCK_open)); if (!error) { mysql_update_log.write(thd, thd->query, thd->query_length); @@ -1217,7 +1223,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } send_ok(&thd->net); } - DBUG_RETURN(error); } @@ -1460,6 +1465,53 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (table->tmp_table) create_info->options|=HA_LEX_CREATE_TMP_TABLE; + /* + Handling of symlinked tables: + If no rename: + Create new data file and index file on the same disk as the + old data and index files. + Copy data. + Rename new data file over old data file and new index file over + old index file. + Symlinks are not changed. + + If rename: + Create new data file and index file on the same disk as the + old data and index files. Create also symlinks to point at + the new tables. + Copy data. + At end, rename temporary tables and symlinks to temporary table + to final table name. + Remove old table and old symlinks + + If rename is made to another database: + Create new tables in new database. + Copy data. + Remove old table and symlinks. + */ + + if (!strcmp(db, new_db)) // Ignore symlink if db changed + { + if (create_info->index_file_name) + { + /* Fix index_file_name to have 'tmp_name' as basename */ + strmov(index_file, tmp_name); + create_info->index_file_name=fn_same(index_file, + create_info->index_file_name, + 1); + } + if (create_info->data_file_name) + { + /* Fix data_file_name to have 'tmp_name' as basename */ + strmov(data_file, tmp_name); + create_info->data_file_name=fn_same(data_file, + create_info->data_file_name, + 1); + } + } + else + create_info->data_file_name=create_info->index_file_name=0; + if ((error=mysql_create_table(thd, new_db, tmp_name, create_info, create_list,key_list,1,1))) // no logging @@ -1705,8 +1757,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (from->found_records = filesort(&from, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + (from->found_records = filesort(from, sortorder, length, + (SQL_SELECT *) 0, 0L, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) goto err; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index c4c2855a63e..651fd52d6c3 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -96,8 +96,7 @@ void print_cached_tables(void) } -void TEST_filesort(TABLE **table,SORT_FIELD *sortorder,uint s_length, - ha_rows special) +void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special) { char buff[256],buff2[256]; String str(buff,sizeof(buff)),out(buff2,sizeof(buff2)); diff --git a/sql/sql_union.cc b/sql/sql_union.cc new file mode 100644 index 00000000000..a0a6704b631 --- /dev/null +++ b/sql/sql_union.cc @@ -0,0 +1,222 @@ +/* Copyright (C) 2000 MySQL AB + + 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 */ + + +/* + UNION of select's + UNION's were introduced by Monty and Sinisa <sinisa@mysql.com> +*/ + + +#include "mysql_priv.h" +#include "sql_select.h" + + +int mysql_union(THD *thd, LEX *lex,select_result *result) +{ + SELECT_LEX *sl, *last_sl; + ORDER *order; + List<Item> item_list; + TABLE *table; + TABLE_LIST *first_table, result_table_list; + TMP_TABLE_PARAM tmp_table_param; + select_union *union_result; + int res; + uint elements; + DBUG_ENTER("mysql_union"); + + /* Fix tables--to-be-unioned-from list to point at opened tables */ + for (sl=&lex->select_lex; sl; sl=sl->next) + { + for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; + cursor; + cursor=cursor->next) + cursor->table= ((TABLE_LIST*) cursor->table)->table; + } + + /* Find last select part as it's here ORDER BY and GROUP BY is stored */ + elements= lex->select_lex.item_list.elements; + for (last_sl= &lex->select_lex; + last_sl->next; + last_sl=last_sl->next) + { + if (elements != last_sl->next->item_list.elements) + { + my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,MYF(0)); + return -1; + } + } + + if (lex->select_lex.options & SELECT_DESCRIBE) + { + for (sl= &lex->select_lex; sl; sl=sl->next) + { + lex->select=sl; + res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first, + sl->item_list, + sl->where, + sl->ftfunc_list, + (ORDER*) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl->options | thd->options | SELECT_NO_UNLOCK | SELECT_DESCRIBE, + result); + } + return 0; + } + + order = (ORDER *) last_sl->order_list.first; + { + Item *item; + List_iterator<Item> it(lex->select_lex.item_list); + + /* Create a list of items that will be in the result set */ + first_table= (TABLE_LIST*) lex->select_lex.table_list.first; + while ((item= it++)) + if (item_list.push_back(item)) + DBUG_RETURN(-1); + if (setup_fields(thd,first_table,item_list,0,0,1)) + DBUG_RETURN(-1); + } + bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); + tmp_table_param.field_count=elements; + if (!(table=create_tmp_table(thd, &tmp_table_param, item_list, + (ORDER*) 0, !lex->union_option, + 1, 0, + (lex->select_lex.options | thd->options | + TMP_TABLE_ALL_COLUMNS)))) + DBUG_RETURN(-1); + table->file->extra(HA_EXTRA_WRITE_CACHE); + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + bzero((char*) &result_table_list,sizeof(result_table_list)); + result_table_list.db= (char*) ""; + result_table_list.real_name=result_table_list.name=(char*) "union"; + result_table_list.table=table; + + if (!(union_result=new select_union(table))) + { + res= -1; + goto exit; + } + for (sl= &lex->select_lex; sl; sl=sl->next) + { + thd->offset_limit=sl->offset_limit; + thd->select_limit=sl->select_limit+sl->offset_limit; + if (thd->select_limit < sl->select_limit) + thd->select_limit= HA_POS_ERROR; // no limit + if (thd->select_limit == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first, + sl->item_list, + sl->where, + sl->ftfunc_list, + (ORDER*) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + if (res) + goto exit; + } + if (union_result->flush()) + { + res= 1; // Error is already sent + goto exit; + } + delete union_result; + + /* Send result to 'result' */ + res =-1; + { + /* Create a list of fields in the temporary table */ + List_iterator<Item> it(item_list); + Field **field; + List<Item_func_match> ftfunc_list; + ftfunc_list.empty(); + + for (field=table->field ; *field ; field++) + { + (void) it++; + (void) it.replace(new Item_field(*field)); + } + if (!thd->fatal_error) // Check if EOM + res=mysql_select(thd,&result_table_list, + item_list, NULL, ftfunc_list, order, + (ORDER*) NULL, NULL, (ORDER*) NULL, + thd->options, result); + } + +exit: + free_tmp_table(thd,table); + DBUG_RETURN(res); +} + + +/*************************************************************************** +** store records in temporary table for UNION +***************************************************************************/ + +select_union::select_union(TABLE *table_par) + :table(table_par) +{ + bzero((char*) &info,sizeof(info)); + /* + We can always use DUP_IGNORE because the temporary table will only + contain a unique key if we are using not using UNION ALL + */ + info.handle_duplicates=DUP_IGNORE; +} + +select_union::~select_union() +{ +} + +int select_union::prepare(List<Item> &list) +{ + return 0; +} + +bool select_union::send_data(List<Item> &values) +{ + if (thd->offset_limit) + { // using limit offset,count + thd->offset_limit--; + return 0; + } + fill_record(table->field,values); + return write_record(table,&info) ? 1 : 0; +} + +bool select_union::send_eof() +{ + return 0; +} + +bool select_union::flush() +{ + int error,error2; + error=table->file->extra(HA_EXTRA_NO_CACHE); + if (error) + { + table->file->print_error(error,MYF(0)); + ::send_error(&thd->net); + return 1; + } + return 0; +} diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 2e9a3c5e355..fbf8239bf69 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + 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 */ @@ -40,8 +40,12 @@ static bool compare_record(TABLE *table, ulong query_id) } -int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, - List<Item> &values, COND *conds, +int mysql_update(THD *thd, + TABLE_LIST *table_list, + List<Item> &fields, + List<Item> &values, + COND *conds, + ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates, thr_lock_type lock_type) @@ -86,7 +90,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, /* Check the fields we are going to modify */ table->grant.want_privilege=want_privilege; - if (setup_fields(thd,table_list,fields,1,0)) + if (setup_fields(thd,table_list,fields,1,0,0)) DBUG_RETURN(-1); /* purecov: inspected */ if (table->timestamp_field) { @@ -99,7 +103,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, /* Check values */ table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); - if (setup_fields(thd,table_list,values,0,0)) + if (setup_fields(thd,table_list,values,0,0,0)) { table->time_stamp=save_time_stamp; // Restore timestamp pointer DBUG_RETURN(-1); /* purecov: inspected */ @@ -125,7 +129,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, /* If running in safe sql mode, don't allow updates without keys */ if (!table->quick_keys) { - thd->lex.options|=QUERY_NO_INDEX_USED; + thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR) { delete select; @@ -164,6 +168,34 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } + + if (order) + { + uint length; + SORT_FIELD *sortorder; + TABLE_LIST tables; + List<Item> fields; + List<Item> all_fields; + ha_rows examined_rows; + + bzero((char*) &tables,sizeof(tables)); + tables.table = table; + + table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + if (setup_order(thd, &tables, fields, all_fields, order) || + !(sortorder=make_unireg_sortorder(order, &length)) || + (table->found_records = filesort(table, sortorder, length, + (SQL_SELECT *) 0, 0L, + HA_POS_ERROR, &examined_rows)) + == HA_POS_ERROR) + { + delete select; + table->time_stamp=save_time_stamp; // Restore timestamp pointer + DBUG_RETURN(-1); + } + } + init_read_record(&info,thd,table,select,0,1); thd->proc_info="searching"; @@ -181,7 +213,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, } else { - if (!(test_flags & 512)) /* For debugging */ + if (!(test_flags & 512)) /* For debugging */ { DBUG_DUMP("record",(char*) table->record[0],table->reclength); } @@ -203,7 +235,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, select->cond=0; } else - { + { select= new SQL_SELECT; select->head=table; } @@ -214,7 +246,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields, { delete select; table->time_stamp=save_time_stamp; // Restore timestamp pointer - DBUG_RETURN(-1); + DBUG_RETURN(-1); } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5a1c6baf1e4..2318a6d309e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -21,6 +21,7 @@ #define YYINITDEPTH 100 #define YYMAXDEPTH 3200 /* Because of 64K stack */ #define Lex current_lex +#define Select Lex->select #include "mysql_priv.h" #include "slave.h" #include "sql_acl.h" @@ -72,6 +73,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token END_OF_INPUT +%token CLOSE_SYM +%token HANDLER_SYM +%token LAST_SYM +%token NEXT_SYM +%token PREV_SYM +%token SQL_CALC_FOUND_ROWS + %token EQ %token EQUAL_SYM %token GE @@ -123,7 +131,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token LOCK_SYM %token LOCKS_SYM %token UNLOCK_SYM +%token BINLOG_SYM +%token EVENTS_SYM +%token ABORT_SYM %token ACTION %token AGGREGATE_SYM %token ALL @@ -143,6 +154,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token CASCADE %token CHECKSUM_SYM %token CHECK_SYM +%token CIPHER %token COMMITTED_SYM %token COLUMNS %token COLUMN_SYM @@ -155,8 +167,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DELAY_KEY_WRITE_SYM %token DESC %token DESCRIBE +%token DIRECTORY_SYM %token DISTINCT +%token DISABLE_SYM %token DYNAMIC_SYM +%token ENABLE_SYM %token ENCLOSED %token ESCAPED %token ESCAPE_SYM @@ -185,6 +200,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token IDENT %token IGNORE_SYM %token INDEX +%token INDEXES %token INFILE %token INNER_SYM %token INNOBASE_SYM @@ -192,6 +208,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token IN_SYM %token ISOLATION %token ISAM_SYM +%token ISSUER %token JOIN_SYM %token KEYS %token KEY_SYM @@ -210,9 +227,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MASTER_USER_SYM %token MASTER_LOG_FILE_SYM %token MASTER_LOG_POS_SYM +%token MASTER_LOG_SEQ_SYM %token MASTER_PASSWORD_SYM %token MASTER_PORT_SYM %token MASTER_CONNECT_RETRY_SYM +%token MASTER_SERVER_ID_SYM %token MATCH %token MAX_ROWS %token MEDIUM_SYM @@ -221,6 +240,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MYISAM_SYM %token NATIONAL_SYM %token NATURAL +%token NEW_SYM %token NCHAR_SYM %token NOT %token NO_SYM @@ -254,6 +274,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token RELOAD %token RENAME %token REPEATABLE_SYM +%token REQUIRE_SYM %token RESTORE_SYM %token RESTRICT %token REVOKE @@ -267,6 +288,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token STARTING %token STATUS_SYM %token STRAIGHT_JOIN +%token SUBJECT_SYM %token TABLES %token TABLE_SYM %token TEMPORARY @@ -456,12 +478,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); opt_escape %type <string> - text_string + text_string %type <num> type int_type real_type order_dir opt_field_spec set_option lock_option udf_type if_exists opt_local opt_table_options table_options - table_option opt_if_not_exists + table_option opt_if_not_exists %type <ulong_num> ULONG_NUM raid_types @@ -518,13 +540,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); select_item_list select_item values_list no_braces limit_clause delete_limit_clause fields opt_values values procedure_list procedure_list2 procedure_item - when_list2 expr_list2 + when_list2 expr_list2 handler opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option field_opt_list opt_binary table_lock_list table_lock varchar references opt_on_delete opt_on_delete_list opt_on_delete_item use opt_delete_options opt_delete_option - opt_outer table_list table opt_option opt_place opt_low_priority + opt_outer table_list table_name opt_option opt_place opt_low_priority opt_attribute opt_attribute_list attribute column_list column_list_id opt_column_list grant_privileges opt_table user_list grant_option grant_privilege grant_privilege_list @@ -532,7 +554,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); equal optional_braces opt_key_definition key_usage_list2 opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as - END_OF_INPUT + handler_rkey_function handler_rkey_mode handler_read_or_scan + single_multi table_wild_list table_wild_one opt_wild union union_list + precision union_option +END_OF_INPUT %type <NONE> '-' '+' '*' '/' '%' '(' ')' @@ -581,6 +606,7 @@ verb_clause: | slave | show | truncate + | handler | unlock | update | use @@ -637,7 +663,6 @@ master_def: } - /* create a table */ create: @@ -661,36 +686,41 @@ create: | CREATE opt_unique_or_fulltext INDEX ident ON table_ident { - Lex->sql_command= SQLCOM_CREATE_INDEX; + LEX *lex=Lex; + lex->sql_command= SQLCOM_CREATE_INDEX; if (!add_table_to_list($6,NULL,1)) YYABORT; - Lex->create_list.empty(); - Lex->key_list.empty(); - Lex->col_list.empty(); - Lex->change=NullS; + lex->create_list.empty(); + lex->key_list.empty(); + lex->col_list.empty(); + lex->change=NullS; } '(' key_list ')' { - Lex->key_list.push_back(new Key($2,$4.str,Lex->col_list)); - Lex->col_list.empty(); + LEX *lex=Lex; + lex->key_list.push_back(new Key($2,$4.str,lex->col_list)); + lex->col_list.empty(); } | CREATE DATABASE opt_if_not_exists ident { - Lex->sql_command=SQLCOM_CREATE_DB; - Lex->name=$4.str; - Lex->create_info.options=$3; + LEX *lex=Lex; + lex->sql_command=SQLCOM_CREATE_DB; + lex->name=$4.str; + lex->create_info.options=$3; } | CREATE udf_func_type UDF_SYM ident { - Lex->sql_command = SQLCOM_CREATE_FUNCTION; - Lex->udf.name=$4.str; - Lex->udf.name_length=$4.length; - Lex->udf.type= $2; + LEX *lex=Lex; + lex->sql_command = SQLCOM_CREATE_FUNCTION; + lex->udf.name=$4.str; + lex->udf.name_length=$4.length; + lex->udf.type= $2; } UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING { - Lex->udf.returns=(Item_result) $7; - Lex->udf.dl=$9.str; + LEX *lex=Lex; + lex->udf.returns=(Item_result) $7; + lex->udf.dl=$9.str; } create2: @@ -701,10 +731,11 @@ create3: /* empty */ {} | opt_duplicate opt_as SELECT_SYM { - Lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; - mysql_init_select(Lex); + LEX *lex=Lex; + lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; + mysql_init_select(lex); } - select_options select_item_list opt_select_from {} + select_options select_item_list opt_select_from union {} opt_as: /* empty */ {} @@ -752,15 +783,17 @@ create_table_option: { /* Move the union list to the merge_list */ LEX *lex=Lex; - TABLE_LIST *table_list= (TABLE_LIST*) lex->table_list.first; - lex->create_info.merge_list= lex->table_list; + TABLE_LIST *table_list= (TABLE_LIST*) lex->select->table_list.first; + lex->create_info.merge_list= lex->select->table_list; lex->create_info.merge_list.elements--; lex->create_info.merge_list.first= (byte*) (table_list->next); - lex->table_list.elements=1; - lex->table_list.next= (byte**) &(table_list->next); + lex->select->table_list.elements=1; + lex->select->table_list.next= (byte**) &(table_list->next); table_list->next=0; lex->create_info.used_fields|= HA_CREATE_USED_UNION; } + | DATA_SYM DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.data_file_name= $4.str; } + | INDEX DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.index_file_name= $4.str; } table_types: ISAM_SYM { $$= DB_TYPE_ISAM; } @@ -768,7 +801,7 @@ table_types: | MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; } | HEAP_SYM { $$= DB_TYPE_HEAP; } | BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; } - | INNOBASE_SYM { $$= DB_TYPE_INNOBASE; } + | INNOBASE_SYM { $$= DB_TYPE_INNODB; } | GEMINI_SYM { $$= DB_TYPE_GEMINI; } row_types: @@ -808,8 +841,9 @@ field_list_item: } | key_type opt_ident '(' key_list ')' { - Lex->key_list.push_back(new Key($1,$2,Lex->col_list)); - Lex->col_list.empty(); /* Alloced by sql_alloc */ + LEX *lex=Lex; + lex->key_list.push_back(new Key($1,$2,lex->col_list)); + lex->col_list.empty(); /* Alloced by sql_alloc */ } | opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references { @@ -827,16 +861,18 @@ opt_constraint: field_spec: field_ident { - Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0; - Lex->default_value=0; + LEX *lex=Lex; + lex->length=lex->dec=0; lex->type=0; lex->interval=0; + lex->default_value=0; } type opt_attribute { + LEX *lex=Lex; if (add_field_to_list($1.str, (enum enum_field_types) $3, - Lex->length,Lex->dec,Lex->type, - Lex->default_value,Lex->change, - Lex->interval)) + lex->length,lex->dec,lex->type, + lex->default_value,lex->change, + lex->interval)) YYABORT; } @@ -888,12 +924,14 @@ type: { $$=FIELD_TYPE_DECIMAL;} | ENUM {Lex->interval_list.empty();} '(' string_list ')' { - Lex->interval=typelib(Lex->interval_list); + LEX *lex=Lex; + lex->interval=typelib(lex->interval_list); $$=FIELD_TYPE_ENUM; } | SET { Lex->interval_list.empty();} '(' string_list ')' { - Lex->interval=typelib(Lex->interval_list); + LEX *lex=Lex; + lex->interval=typelib(lex->interval_list); $$=FIELD_TYPE_SET; } @@ -925,7 +963,14 @@ real_type: float_options: /* empty */ {} | '(' NUM ')' { Lex->length=$2.str; } - | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; } + | precision {} + +precision: + '(' NUM ',' NUM ')' + { + LEX *lex=Lex; + lex->length=$2.str; lex->dec=$4.str; + } field_options: /* empty */ {} @@ -945,7 +990,7 @@ opt_len: opt_precision: /* empty */ {} - | '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; } + | precision {} opt_attribute: /* empty */ {} @@ -1012,6 +1057,7 @@ key_or_index: keys_or_index: KEYS {} | INDEX {} + | INDEXES {} opt_unique_or_fulltext: /* empty */ { $$= Key::MULTIPLE; } @@ -1052,12 +1098,14 @@ alter: lex->col_list.empty(); lex->drop_list.empty(); lex->alter_list.empty(); - lex->order_list.elements=0; - lex->order_list.first=0; - lex->order_list.next= (byte**) &lex->order_list.first; - lex->db=lex->name=0; + lex->select->order_list.elements=0; + lex->select->order_list.first=0; + lex->select->order_list.next= (byte**) &lex->select->order_list.first; + lex->select->db=lex->name=0; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.db_type= DB_TYPE_DEFAULT; + lex->alter_keys_onoff=LEAVE_AS_IS; + lex->simple_alter=1; } alter_list @@ -1066,42 +1114,77 @@ alter_list: | alter_list ',' alter_list_item add_column: - ADD opt_column { Lex->change=0;} + ADD opt_column { Lex->change=0; } alter_list_item: - add_column field_list_item opt_place - | add_column '(' field_list ')' - | CHANGE opt_column field_ident { Lex->change= $3.str; } field_spec + add_column field_list_item opt_place { Lex->simple_alter=0; } + | add_column '(' field_list ')' { Lex->simple_alter=0; } + | CHANGE opt_column field_ident + { + LEX *lex=Lex; + lex->change= $3.str; lex->simple_alter=0; + } + field_spec | MODIFY_SYM opt_column field_ident { - Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0; - Lex->default_value=0; + LEX *lex=Lex; + lex->length=lex->dec=0; lex->type=0; lex->interval=0; + lex->default_value=0; + lex->simple_alter=0; } type opt_attribute { + LEX *lex=Lex; if (add_field_to_list($3.str, (enum enum_field_types) $5, - Lex->length,Lex->dec,Lex->type, - Lex->default_value, $3.str, - Lex->interval)) + lex->length,lex->dec,lex->type, + lex->default_value, $3.str, + lex->interval)) YYABORT; + lex->simple_alter=0; } | DROP opt_column field_ident opt_restrict - { Lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN, - $3.str)); } - | DROP PRIMARY_SYM KEY_SYM { Lex->drop_primary=1; } - | DROP FOREIGN KEY_SYM opt_ident {} + { + LEX *lex=Lex; + lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN, + $3.str)); lex->simple_alter=0; + } + | DROP PRIMARY_SYM KEY_SYM + { + LEX *lex=Lex; + lex->drop_primary=1; lex->simple_alter=0; + } + | DROP FOREIGN KEY_SYM opt_ident { Lex->simple_alter=0; } | DROP key_or_index field_ident - { Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, - $3.str)); } + { + LEX *lex=Lex; + lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, + $3.str)); + lex->simple_alter=0; + } + | DISABLE_SYM KEYS { Lex->alter_keys_onoff=DISABLE; } + | ENABLE_SYM KEYS { Lex->alter_keys_onoff=ENABLE; } | ALTER opt_column field_ident SET DEFAULT literal - { Lex->alter_list.push_back(new Alter_column($3.str,$6)); } + { + LEX *lex=Lex; + lex->alter_list.push_back(new Alter_column($3.str,$6)); + lex->simple_alter=0; + } | ALTER opt_column field_ident DROP DEFAULT - { Lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); } + { + LEX *lex=Lex; + lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); + lex->simple_alter=0; + } | RENAME opt_to table_alias table_ident - { Lex->db=$4->db.str ; Lex->name= $4->table.str; } - | create_table_options - | order_clause + { + LEX *lex=Lex; + lex->select->db=$4->db.str; + lex->name= $4->table.str; + lex->simple_alter=0; + } + | create_table_options { Lex->simple_alter=0; } + | order_clause { Lex->simple_alter=0; } opt_column: /* empty */ {} @@ -1129,14 +1212,16 @@ opt_to: slave: SLAVE START_SYM { - Lex->sql_command = SQLCOM_SLAVE_START; - Lex->type = 0; + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_START; + lex->type = 0; } | SLAVE STOP_SYM { - Lex->sql_command = SQLCOM_SLAVE_STOP; - Lex->type = 0; + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_STOP; + lex->type = 0; }; restore: @@ -1162,8 +1247,9 @@ backup: repair: REPAIR table_or_tables { - Lex->sql_command = SQLCOM_REPAIR; - Lex->check_opt.init(); + LEX *lex=Lex; + lex->sql_command = SQLCOM_REPAIR; + lex->check_opt.init(); } table_list opt_mi_check_type @@ -1187,24 +1273,27 @@ mi_check_type: analyze: ANALYZE_SYM table_or_tables { - Lex->sql_command = SQLCOM_ANALYZE; - Lex->check_opt.init(); + LEX *lex=Lex; + lex->sql_command = SQLCOM_ANALYZE; + lex->check_opt.init(); } table_list opt_mi_check_type check: CHECK_SYM table_or_tables { - Lex->sql_command = SQLCOM_CHECK; - Lex->check_opt.init(); + LEX *lex=Lex; + lex->sql_command = SQLCOM_CHECK; + lex->check_opt.init(); } table_list opt_mi_check_type optimize: OPTIMIZE table_or_tables { - Lex->sql_command = SQLCOM_OPTIMIZE; - Lex->check_opt.init(); + LEX *lex=Lex; + lex->sql_command = SQLCOM_OPTIMIZE; + lex->check_opt.init(); } table_list opt_mi_check_type @@ -1234,15 +1323,20 @@ table_to_table: select: SELECT_SYM { + Lex->sql_command= SQLCOM_SELECT; + } + select_part2; + +select_part2: + { LEX *lex=Lex; - lex->sql_command= SQLCOM_SELECT; lex->lock_option=TL_READ; - mysql_init_select(lex); + mysql_init_select(lex); } - select_options select_item_list select_into select_lock_type + select_options select_item_list select_into select_lock_type union select_into: - /* empty */ + limit_clause {} | select_from | opt_into select_from | select_from opt_into @@ -1260,19 +1354,20 @@ select_option_list: | select_option select_option: - STRAIGHT_JOIN { Lex->options|= SELECT_STRAIGHT_JOIN; } + STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; } | HIGH_PRIORITY { Lex->lock_option= TL_READ_HIGH_PRIORITY; } - | DISTINCT { Lex->options|= SELECT_DISTINCT; } - | SQL_SMALL_RESULT { Lex->options|= SELECT_SMALL_RESULT; } - | SQL_BIG_RESULT { Lex->options|= SELECT_BIG_RESULT; } - | SQL_BUFFER_RESULT { Lex->options|= OPTION_BUFFER_RESULT; } + | DISTINCT { Select->options|= SELECT_DISTINCT; } + | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } + | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; } + | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; } + | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; } | ALL {} select_lock_type: /* empty */ | FOR_SYM UPDATE_SYM { Lex->lock_option= TL_WRITE; } - | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM + | IN_SYM SHARE_SYM MODE_SYM { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; } select_item_list: @@ -1452,10 +1547,10 @@ simple_expr: | '(' expr ')' { $$= $2; } | '{' ident expr '}' { $$= $3; } | MATCH '(' ident_list ')' AGAINST '(' expr ')' - { Lex->ftfunc_list.push_back( + { Select->ftfunc_list.push_back( (Item_func_match *)($$=new Item_func_match(*$3,$7))); } | MATCH ident_list AGAINST '(' expr ')' - { Lex->ftfunc_list.push_back( + { Select->ftfunc_list.push_back( (Item_func_match *)($$=new Item_func_match(*$2,$5))); } | BINARY expr %prec NEG { $$= new Item_func_binary($2); } | CASE_SYM opt_expr WHEN_SYM when_list opt_else END @@ -1686,30 +1781,30 @@ sum_expr: { $$=new Item_sum_sum($3); } in_sum_expr: - { Lex->in_sum_expr++ } + { Select->in_sum_expr++ } expr { - Lex->in_sum_expr--; + Select->in_sum_expr--; $$=$2; } expr_list: - { Lex->expr_list.push_front(new List<Item>); } + { Select->expr_list.push_front(new List<Item>); } expr_list2 - { $$= Lex->expr_list.pop(); } + { $$= Select->expr_list.pop(); } expr_list2: - expr { Lex->expr_list.head()->push_back($1); } - | expr_list2 ',' expr { Lex->expr_list.head()->push_back($3); } + expr { Select->expr_list.head()->push_back($1); } + | expr_list2 ',' expr { Select->expr_list.head()->push_back($3); } ident_list: - { Lex->expr_list.push_front(new List<Item>); } + { Select->expr_list.push_front(new List<Item>); } ident_list2 - { $$= Lex->expr_list.pop(); } + { $$= Select->expr_list.pop(); } ident_list2: - simple_ident { Lex->expr_list.head()->push_back($1); } - | ident_list2 ',' simple_ident { Lex->expr_list.head()->push_back($3); } + simple_ident { Select->expr_list.head()->push_back($1); } + | ident_list2 ',' simple_ident { Select->expr_list.head()->push_back($3); } opt_expr: /* empty */ { $$= NULL; } @@ -1720,20 +1815,22 @@ opt_else: | ELSE expr { $$= $2; } when_list: - { Lex->when_list.push_front(new List<Item>) } + { Select->when_list.push_front(new List<Item>) } when_list2 - { $$= Lex->when_list.pop(); } + { $$= Select->when_list.pop(); } when_list2: expr THEN_SYM expr { - Lex->when_list.head()->push_back($1); - Lex->when_list.head()->push_back($3); + SELECT_LEX *sel=Select; + sel->when_list.head()->push_back($1); + sel->when_list.head()->push_back($3); } | when_list2 WHEN_SYM expr THEN_SYM expr { - Lex->when_list.head()->push_back($3); - Lex->when_list.head()->push_back($5); + SELECT_LEX *sel=Select; + sel->when_list.head()->push_back($3); + sel->when_list.head()->push_back($5); } opt_pad: @@ -1748,15 +1845,21 @@ join_table_list: | join_table_list INNER_SYM JOIN_SYM join_table ON expr { add_join_on($4,$6); $$=$4; } | join_table_list INNER_SYM JOIN_SYM join_table - { Lex->db1=$1->db; Lex->table1=$1->name; - Lex->db2=$4->db; Lex->table2=$4->name; } + { + SELECT_LEX *sel=Select; + sel->db1=$1->db; sel->table1=$1->name; + sel->db2=$4->db; sel->table2=$4->name; + } USING '(' using_list ')' { add_join_on($4,$8); $$=$4; } | join_table_list LEFT opt_outer JOIN_SYM join_table ON expr { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list LEFT opt_outer JOIN_SYM join_table - { Lex->db1=$1->db; Lex->table1=$1->name; - Lex->db2=$5->db; Lex->table2=$5->name; } + { + SELECT_LEX *sel=Select; + sel->db1=$1->db; sel->table1=$1->name; + sel->db2=$5->db; sel->table2=$5->name; + } USING '(' using_list ')' { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table @@ -1764,8 +1867,11 @@ join_table_list: | join_table_list RIGHT opt_outer JOIN_SYM join_table ON expr { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } | join_table_list RIGHT opt_outer JOIN_SYM join_table - { Lex->db1=$1->db; Lex->table1=$1->name; - Lex->db2=$5->db; Lex->table2=$5->name; } + { + SELECT_LEX *sel=Select; + sel->db1=$1->db; sel->table1=$1->name; + sel->db2=$5->db; sel->table2=$5->name; + } USING '(' using_list ')' { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table @@ -1779,10 +1885,16 @@ normal_join: | CROSS JOIN_SYM {} join_table: - { Lex->use_index_ptr=Lex->ignore_index_ptr=0; } + { + SELECT_LEX *sel=Select; + sel->use_index_ptr=sel->ignore_index_ptr=0; + } table_ident opt_table_alias opt_key_definition - { if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, Lex->use_index_ptr, - Lex->ignore_index_ptr))) YYABORT; } + { + SELECT_LEX *sel=Select; + if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr, + sel->ignore_index_ptr))) YYABORT; + } | '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}' { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } @@ -1793,30 +1905,41 @@ opt_outer: opt_key_definition: /* empty */ {} | USE_SYM key_usage_list - { Lex->use_index= *$2; Lex->use_index_ptr= &Lex->use_index; } + { + SELECT_LEX *sel=Select; + sel->use_index= *$2; + sel->use_index_ptr= &sel->use_index; + } | IGNORE_SYM key_usage_list - { Lex->ignore_index= *$2; Lex->ignore_index_ptr= &Lex->ignore_index;} + { + SELECT_LEX *sel=Select; + sel->ignore_index= *$2; + sel->ignore_index_ptr= &sel->ignore_index; + } key_usage_list: - key_or_index { Lex->interval_list.empty() } '(' key_usage_list2 ')' - { $$= &Lex->interval_list; } + key_or_index { Select->interval_list.empty() } '(' key_usage_list2 ')' + { $$= &Select->interval_list; } key_usage_list2: key_usage_list2 ',' ident - { Lex->interval_list.push_back(new String((const char*) $3.str,$3.length)); } + { Select->interval_list.push_back(new String((const char*) $3.str,$3.length)); } | ident - { Lex->interval_list.push_back(new String((const char*) $1.str,$1.length)); } + { Select->interval_list.push_back(new String((const char*) $1.str,$1.length)); } | PRIMARY_SYM - { Lex->interval_list.push_back(new String("PRIMARY",7)); } + { Select->interval_list.push_back(new String("PRIMARY",7)); } using_list: ident - { if (!($$= new Item_func_eq(new Item_field(Lex->db1,Lex->table1, $1.str), new Item_field(Lex->db2,Lex->table2,$1.str)))) + { + SELECT_LEX *sel=Select; + if (!($$= new Item_func_eq(new Item_field(sel->db1,sel->table1, $1.str), new Item_field(sel->db2,sel->table2,$1.str)))) YYABORT; } | using_list ',' ident { - if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(Lex->db1,Lex->table1,$3.str), new Item_field(Lex->db2,Lex->table2,$3.str)), $1))) + SELECT_LEX *sel=Select; + if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) YYABORT; } @@ -1847,13 +1970,16 @@ opt_table_alias: where_clause: - /* empty */ { Lex->where= 0; } - | WHERE expr { Lex->where= $2; } + /* empty */ { Select->where= 0; } + | WHERE expr { Select->where= $2; } having_clause: /* empty */ - | HAVING { Lex->create_refs=1; } expr - { Lex->having= $3; Lex->create_refs=0; } + | HAVING { Select->create_refs=1; } expr + { + SELECT_LEX *sel=Select; + sel->having= $3; sel->create_refs=0; + } opt_escape: ESCAPE_SYM TEXT_STRING { $$= $2.str; } @@ -1883,7 +2009,7 @@ opt_order_clause: | order_clause order_clause: - ORDER_SYM BY { Lex->sort_default=1; } order_list + ORDER_SYM BY { Select->sort_default=1; } order_list order_list: order_list ',' order_ident order_dir @@ -1893,38 +2019,46 @@ order_list: order_dir: /* empty */ { $$ = 1; } - | ASC { $$ = Lex->sort_default=1; } - | DESC { $$ = Lex->sort_default=0; } + | ASC { $$ = Select->sort_default=1; } + | DESC { $$ = Select->sort_default=0; } limit_clause: /* empty */ { - Lex->select_limit= current_thd->default_select_limit; - Lex->offset_limit= 0L; + SELECT_LEX *sel=Select; + sel->select_limit= (Lex->sql_command == SQLCOM_HA_READ) ? + 1 : current_thd->default_select_limit; + sel->offset_limit= 0L; } | LIMIT ULONG_NUM - { Lex->select_limit= $2; Lex->offset_limit=0L; } + { + SELECT_LEX *sel=Select; + sel->select_limit= $2; sel->offset_limit=0L; + } | LIMIT ULONG_NUM ',' ULONG_NUM - { Lex->select_limit= $4; Lex->offset_limit=$2; } + { + SELECT_LEX *sel=Select; + sel->select_limit= $4; sel->offset_limit=$2; + } delete_limit_clause: /* empty */ { - Lex->select_limit= HA_POS_ERROR; + Select->select_limit= HA_POS_ERROR; } | LIMIT ULONGLONG_NUM - { Lex->select_limit= (ha_rows) $2; } + { Select->select_limit= (ha_rows) $2; } ULONG_NUM: - NUM { $$= strtoul($1.str,NULL,10); } - | REAL_NUM { $$= strtoul($1.str,NULL,10); } + NUM { $$= strtoul($1.str,NULL,10); } + | REAL_NUM { $$= strtoul($1.str,NULL,10); } | FLOAT_NUM { $$= strtoul($1.str,NULL,10); } ULONGLONG_NUM: - NUM { $$= (ulonglong) strtoul($1.str,NULL,10); } - | LONG_NUM { $$= strtoull($1.str,NULL,10); } - | REAL_NUM { $$= strtoull($1.str,NULL,10); } + NUM { $$= (ulonglong) strtoul($1.str,NULL,10); } + | LONG_NUM { $$= strtoull($1.str,NULL,10); } + | REAL_NUM { $$= strtoull($1.str,NULL,10); } | FLOAT_NUM { $$= strtoull($1.str,NULL,10); } procedure_clause: @@ -1979,36 +2113,40 @@ opt_into: drop: DROP TABLE_SYM if_exists table_list opt_restrict { - Lex->sql_command = SQLCOM_DROP_TABLE; - Lex->drop_if_exists = $3; + LEX *lex=Lex; + lex->sql_command = SQLCOM_DROP_TABLE; + lex->drop_if_exists = $3; } | DROP INDEX ident ON table_ident {} { - Lex->sql_command= SQLCOM_DROP_INDEX; - Lex->drop_list.empty(); - Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, + LEX *lex=Lex; + lex->sql_command= SQLCOM_DROP_INDEX; + lex->drop_list.empty(); + lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, $3.str)); if (!add_table_to_list($5,NULL, 1)) YYABORT; } | DROP DATABASE if_exists ident { - Lex->sql_command= SQLCOM_DROP_DB; - Lex->drop_if_exists=$3; - Lex->name=$4.str; + LEX *lex=Lex; + lex->sql_command= SQLCOM_DROP_DB; + lex->drop_if_exists=$3; + lex->name=$4.str; } | DROP UDF_SYM ident { - Lex->sql_command = SQLCOM_DROP_FUNCTION; - Lex->udf.name=$3.str; + LEX *lex=Lex; + lex->sql_command = SQLCOM_DROP_FUNCTION; + lex->udf.name=$3.str; } table_list: - table - | table_list ',' table + table_name + | table_list ',' table_name -table: +table_name: table_ident { if (!add_table_to_list($1,NULL,1)) YYABORT; } @@ -2041,19 +2179,21 @@ insert2: | insert_table {} insert_table: - table + table_name { - Lex->field_list.empty(); - Lex->many_values.empty(); - Lex->insert_list=0; + LEX *lex=Lex; + lex->field_list.empty(); + lex->many_values.empty(); + lex->insert_list=0; } insert_field_spec: opt_field_spec insert_values {} | SET { - if (!(Lex->insert_list = new List_item) || - Lex->many_values.push_back(Lex->insert_list)) + LEX *lex=Lex; + if (!(lex->insert_list = new List_item) || + lex->many_values.push_back(lex->insert_list)) YYABORT; } ident_eq_list @@ -2077,7 +2217,7 @@ insert_values: lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; mysql_init_select(lex); } - select_options select_item_list select_from select_lock_type {} + select_options select_item_list select_from select_lock_type union {} values_list: values_list ',' no_braces @@ -2091,8 +2231,9 @@ ident_eq_list: ident_eq_value: simple_ident equal expr { - if (Lex->field_list.push_back($1) || - Lex->insert_list->push_back($3)) + LEX *lex=Lex; + if (lex->field_list.push_back($1) || + lex->insert_list->push_back($3)) YYABORT; } @@ -2107,7 +2248,8 @@ no_braces: } opt_values ')' { - if (Lex->many_values.push_back(Lex->insert_list)) + LEX *lex=Lex; + if (lex->many_values.push_back(lex->insert_list)) YYABORT; } @@ -2130,8 +2272,18 @@ values: /* Update rows in a table */ update: - UPDATE_SYM opt_low_priority opt_ignore table SET update_list where_clause delete_limit_clause - { Lex->sql_command = SQLCOM_UPDATE; } + UPDATE_SYM opt_low_priority opt_ignore table_name + SET update_list + where_clause + opt_order_clause + delete_limit_clause + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_UPDATE; + lex->select->order_list.elements=0; + lex->select->order_list.first=0; + lex->select->order_list.next= (byte**) &lex->select->order_list.first; + } update_list: update_list ',' simple_ident equal expr @@ -2153,31 +2305,82 @@ opt_low_priority: delete: DELETE_SYM - { - Lex->sql_command= SQLCOM_DELETE; Lex->options=0; - Lex->lock_option= current_thd->update_lock_default; + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_DELETE; lex->select->options=0; + lex->lock_option= lex->thd->update_lock_default; + lex->select->order_list.elements=0; + lex->select->order_list.first=0; + lex->select->order_list.next= (byte**) &lex->select->order_list.first; } - opt_delete_options FROM table - where_clause delete_limit_clause + opt_delete_options single_multi {} + +single_multi: + FROM table_name where_clause opt_order_clause delete_limit_clause {} + | table_wild_list + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_MULTI_DELETE; + mysql_init_select(lex); + lex->select->select_limit=HA_POS_ERROR; + lex->auxilliary_table_list.elements=0; + lex->auxilliary_table_list.first=0; + lex->auxilliary_table_list.next= (byte**) &(lex->auxilliary_table_list.first); + } + FROM + { + LEX *lex=Lex; + lex->auxilliary_table_list=lex->select_lex.table_list; + lex->select->table_list.elements=0; + lex->select->table_list.first=0; + lex->select->table_list.next= (byte**) &(lex->select->table_list.first); + } join_table_list where_clause + + +table_wild_list: + table_wild_one {} + | table_wild_list ',' table_wild_one {} + +table_wild_one: + ident opt_wild + { + if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE)) + YYABORT; + } + | ident '.' ident opt_wild + { + if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE)) + YYABORT; + } + +opt_wild: + /* empty */ {} + | '.' '*' {} opt_delete_options: - /* empty */ {} + /* empty */ {} | opt_delete_option opt_delete_options {} opt_delete_option: - QUICK { Lex->options|= OPTION_QUICK; } + QUICK { Select->options|= OPTION_QUICK; } | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; } truncate: - TRUNCATE_SYM opt_table_sym table - { Lex->sql_command= SQLCOM_TRUNCATE; Lex->options=0; - Lex->lock_option= current_thd->update_lock_default; } + TRUNCATE_SYM opt_table_sym table_name + { + LEX* lex = Lex; + lex->sql_command= SQLCOM_TRUNCATE; + lex->select->options=0; + lex->select->order_list.elements=0; + lex->select->order_list.first=0; + lex->select->order_list.next= (byte**) &lex->select->order_list.first; + lex->lock_option= current_thd->update_lock_default; } opt_table_sym: /* empty */ | TABLE_SYM - + /* Show things */ show: SHOW { Lex->wild=0;} show_param @@ -2186,18 +2389,26 @@ show_param: DATABASES wild { Lex->sql_command= SQLCOM_SHOW_DATABASES; } | TABLES opt_db wild - { Lex->sql_command= SQLCOM_SHOW_TABLES; Lex->db= $2; Lex->options=0;} + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_TABLES; + lex->select->db= $2; lex->select->options=0; + } | TABLE_SYM STATUS_SYM opt_db wild - { Lex->sql_command= SQLCOM_SHOW_TABLES; - Lex->options|= SELECT_DESCRIBE; - Lex->db= $3; + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_TABLES; + lex->select->options|= SELECT_DESCRIBE; + lex->select->db= $3; } | OPEN_SYM TABLES opt_db wild - { Lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - Lex->db= $3; - Lex->options=0; + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; + lex->select->db= $3; + lex->select->options=0; } - | opt_full COLUMNS FROM table_ident opt_db wild + | opt_full COLUMNS from_or_in table_ident opt_db wild { Lex->sql_command= SQLCOM_SHOW_FIELDS; if ($5) @@ -2205,10 +2416,29 @@ show_param: if (!add_table_to_list($4,NULL,0)) YYABORT; } + | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ + TEXT_STRING AND MASTER_LOG_POS_SYM EQ ULONGLONG_NUM AND + MASTER_LOG_SEQ_SYM EQ ULONG_NUM AND MASTER_SERVER_ID_SYM EQ + ULONG_NUM + { + Lex->sql_command = SQLCOM_SHOW_NEW_MASTER; + Lex->mi.log_file_name = $8.str; + Lex->mi.pos = $12; + Lex->mi.last_log_seq = $16; + Lex->mi.server_id = $20; + } | MASTER_SYM LOGS_SYM { Lex->sql_command = SQLCOM_SHOW_BINLOGS; - } + } + | SLAVE HOSTS_SYM + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS; + } + | BINLOG_SYM EVENTS_SYM binlog_in binlog_from limit_clause + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS; + } | keys_or_index FROM table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS; @@ -2226,8 +2456,12 @@ show_param: | LOGS_SYM { Lex->sql_command= SQLCOM_SHOW_LOGS; } | GRANTS FOR_SYM user - { Lex->sql_command= SQLCOM_SHOW_GRANTS; - Lex->grant_user=$3; Lex->grant_user->password.str=NullS; } + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_GRANTS; + lex->grant_user=$3; + lex->grant_user->password.str=NullS; + } | CREATE TABLE_SYM table_ident { Lex->sql_command = SQLCOM_SHOW_CREATE; @@ -2245,7 +2479,7 @@ show_param: opt_db: /* empty */ { $$= 0; } - | FROM ident { $$= $2.str; } + | from_or_in ident { $$= $2.str; } wild: /* empty */ @@ -2255,18 +2489,32 @@ opt_full: /* empty */ { Lex->verbose=0; } | FULL { Lex->verbose=1; } +from_or_in: + FROM + | IN_SYM + +binlog_in: + /* empty */ { Lex->mi.log_file_name = 0; } + | IN_SYM TEXT_STRING { Lex->mi.log_file_name = $2.str; } + +binlog_from: + /* empty */ { Lex->mi.pos = 4; /* skip magic number */ } + | FROM ULONGLONG_NUM { Lex->mi.pos = $2; } + + /* A Oracle compatible synonym for show */ describe: describe_command table_ident { - Lex->wild=0; - Lex->verbose=0; - Lex->sql_command=SQLCOM_SHOW_FIELDS; + LEX *lex=Lex; + lex->wild=0; + lex->verbose=0; + lex->sql_command=SQLCOM_SHOW_FIELDS; if (!add_table_to_list($2, NULL,0)) YYABORT; } opt_describe_column - | describe_command select { Lex->options|= SELECT_DESCRIBE }; + | describe_command select { Lex->select_lex.options|= SELECT_DESCRIBE }; describe_command: @@ -2282,7 +2530,12 @@ opt_describe_column: /* flush things */ flush: - FLUSH_SYM {Lex->sql_command= SQLCOM_FLUSH; Lex->type=0; } flush_options + FLUSH_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_FLUSH; lex->type=0; + } + flush_options flush_options: flush_options ',' flush_option @@ -2303,8 +2556,11 @@ opt_table_list: | table_list {} reset: - RESET_SYM {Lex->sql_command= SQLCOM_RESET; Lex->type=0; } reset_options - + RESET_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_RESET; lex->type=0; + } reset_options reset_options: reset_options ',' reset_option | reset_option @@ -2314,7 +2570,12 @@ reset_option: | MASTER_SYM { Lex->type|= REFRESH_MASTER; } purge: - PURGE { Lex->sql_command = SQLCOM_PURGE; Lex->type=0;} + PURGE + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_PURGE; + lex->type=0; + } MASTER_SYM LOGS_SYM TO_SYM TEXT_STRING { Lex->to_log = $6.str; @@ -2325,29 +2586,34 @@ purge: kill: KILL_SYM expr { - if ($2->fix_fields(current_thd,0)) - { - send_error(¤t_thd->net, ER_SET_CONSTANTS_ONLY); - YYABORT; - } - Lex->sql_command=SQLCOM_KILL; - Lex->thread_id= (ulong) $2->val_int(); + LEX *lex=Lex; + if ($2->fix_fields(lex->thd,0)) + { + send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY); + YYABORT; + } + lex->sql_command=SQLCOM_KILL; + lex->thread_id= (ulong) $2->val_int(); } /* change database */ use: USE_SYM ident - { Lex->sql_command=SQLCOM_CHANGE_DB; Lex->db= $2.str; } + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_CHANGE_DB; lex->select->db= $2.str; + } /* import, export of files */ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING { - Lex->sql_command= SQLCOM_LOAD; - Lex->local_file= $4; - if (!(Lex->exchange= new sql_exchange($6.str,0))) + LEX *lex=Lex; + lex->sql_command= SQLCOM_LOAD; + lex->local_file= $4; + if (!(lex->exchange= new sql_exchange($6.str,0))) YYABORT; - Lex->field_list.empty(); + lex->field_list.empty(); } opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term opt_ignore_lines opt_field_spec @@ -2363,6 +2629,11 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING YYABORT; } + | + LOAD DATA_SYM FROM MASTER_SYM + { + Lex->sql_command = SQLCOM_LOAD_MASTER_DATA; + } opt_local: /* empty */ { $$=0;} @@ -2390,7 +2661,11 @@ field_term_list: field_term: TERMINATED BY text_string { Lex->exchange->field_term= $3;} | OPTIONALLY ENCLOSED BY text_string - { Lex->exchange->enclosed= $4; Lex->exchange->opt_enclosed=1;} + { + LEX *lex=Lex; + lex->exchange->enclosed= $4; + lex->exchange->opt_enclosed=1; + } | ENCLOSED BY text_string { Lex->exchange->enclosed= $3;} | ESCAPED BY text_string { Lex->exchange->escaped= $3;} @@ -2460,13 +2735,25 @@ order_ident: simple_ident: ident - { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); } + { + SELECT_LEX *sel=Select; + $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); + } | ident '.' ident - { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); } + { + SELECT_LEX *sel=Select; + $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); + } | '.' ident '.' ident - { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); } + { + SELECT_LEX *sel=Select; + $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); + } | ident '.' ident '.' ident - { $$ = !Lex->create_refs || Lex->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); } + { + SELECT_LEX *sel=Select; + $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); + } field_ident: @@ -2483,10 +2770,11 @@ ident: IDENT { $$=$1; } | keyword { + LEX *lex; $$.str=sql_strmake($1.str,$1.length); $$.length=$1.length; - if (Lex->next_state != STATE_END) - Lex->next_state=STATE_OPERATOR_OR_IDENT; + if ((lex=Lex)->next_state != STATE_END) + lex->next_state=STATE_OPERATOR_OR_IDENT; } ident_or_text: @@ -2527,6 +2815,7 @@ keyword: | CHANGED {} | CHECKSUM_SYM {} | CHECK_SYM {} + | CLOSE_SYM {} | COMMENT_SYM {} | COMMIT_SYM {} | COMMITTED_SYM {} @@ -2536,9 +2825,12 @@ keyword: | DATETIME {} | DATE_SYM {} | DAY_SYM {} + | DIRECTORY_SYM {} | DELAY_KEY_WRITE_SYM {} + | DISABLE_SYM {} | DUMPFILE {} | DYNAMIC_SYM {} + | ENABLE_SYM {} | END {} | ENUM {} | ESCAPE_SYM {} @@ -2553,12 +2845,15 @@ keyword: | GEMINI_SYM {} | GLOBAL_SYM {} | HEAP_SYM {} + | HANDLER_SYM {} | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} + | INDEXES {} | ISOLATION {} | ISAM_SYM {} | INNOBASE_SYM {} + | LAST_SYM {} | LEVEL_SYM {} | LOCAL_SYM {} | LOCKS_SYM {} @@ -2582,10 +2877,12 @@ keyword: | MYISAM_SYM {} | NATIONAL_SYM {} | NCHAR_SYM {} + | NEXT_SYM {} | NO_SYM {} | OPEN_SYM {} | PACK_KEYS_SYM {} | PASSWORD {} + | PREV_SYM {} | PROCESS {} | PROCESSLIST_SYM {} | QUICK {} @@ -2631,12 +2928,14 @@ keyword: set: SET opt_option { - THD *thd=current_thd; - Lex->sql_command= SQLCOM_SET_OPTION; - Lex->options=thd->options; - Lex->select_limit=thd->default_select_limit; - Lex->gemini_spin_retries=thd->gemini_spin_retries; - Lex->tx_isolation=thd->tx_isolation; + LEX *lex=Lex; + lex->sql_command= SQLCOM_SET_OPTION; + lex->select->options=lex->thd->options; + lex->select->select_limit=lex->thd->default_select_limit; + lex->gemini_spin_retries=lex->thd->gemini_spin_retries; + lex->tx_isolation=lex->thd->tx_isolation; + lex->option_type=0; + lex->option_list.empty() } option_value_list @@ -2646,36 +2945,41 @@ opt_option: option_value_list: option_value + | GLOBAL_SYM { Lex->option_type=1; } option_value + | LOCAL_SYM { Lex->option_type=0; } option_value | option_value_list ',' option_value option_value: set_option equal NUM { + SELECT_LEX *sel=Select; if (atoi($3.str) == 0) - Lex->options&= ~$1; + sel->options&= ~$1; else - Lex->options|= $1; + sel->options|= $1; } | set_isolation | AUTOCOMMIT equal NUM { + SELECT_LEX *sel=Select; if (atoi($3.str) != 0) /* Test NOT AUTOCOMMIT */ - Lex->options&= ~(OPTION_NOT_AUTO_COMMIT); + sel->options&= ~(OPTION_NOT_AUTO_COMMIT); else - Lex->options|= OPTION_NOT_AUTO_COMMIT; + sel->options|= OPTION_NOT_AUTO_COMMIT; } | SQL_SELECT_LIMIT equal ULONG_NUM { - Lex->select_limit= $3; + Select->select_limit= $3; } | SQL_SELECT_LIMIT equal DEFAULT { - Lex->select_limit= HA_POS_ERROR; + Select->select_limit= HA_POS_ERROR; } | SQL_MAX_JOIN_SIZE equal ULONG_NUM { - current_thd->max_join_size= $3; - Lex->options&= ~OPTION_BIG_SELECTS; + LEX *lex=Lex; + lex->thd->max_join_size= $3; + lex->select->options&= ~OPTION_BIG_SELECTS; } | SQL_MAX_JOIN_SIZE equal DEFAULT { @@ -2744,12 +3048,34 @@ option_value: | SQL_SLAVE_SKIP_COUNTER equal ULONG_NUM { pthread_mutex_lock(&LOCK_slave); - if(slave_running) + if (slave_running) send_error(¤t_thd->net, ER_SLAVE_MUST_STOP); else slave_skip_counter = $3; pthread_mutex_unlock(&LOCK_slave); } + | ident equal DEFAULT + { + LEX *lex=Lex; + lex->option_list.push_back(new Set_option(lex->option_type, + $1.str,$1.length, + (Item*) 0)); + } + | ident equal expr + { + THD *thd=current_thd; + Item *item= $3; + if (item->fix_fields(current_thd,0)) + { + send_error(&thd->net, ER_SET_CONSTANTS_ONLY); + YYABORT; + } + thd->lex.option_list. + push_back(new Set_option(thd->lex.option_type, + $1.str,$1.length, + item)); + } + text_or_password: TEXT_STRING { $$=$1.str;} @@ -2798,7 +3124,10 @@ set_isolation: default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation]; } | SESSION_SYM tx_isolation - { current_thd->session_tx_isolation= Lex->tx_isolation= $2; } + { + LEX *lex=Lex; + lex->thd->session_tx_isolation= lex->tx_isolation= $2; + } | tx_isolation { Lex->tx_isolation= $1; } @@ -2842,27 +3171,82 @@ unlock: UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } +/* +** Handler: direct access to ISAM functions +*/ + +handler: + HANDLER_SYM table_ident OPEN_SYM opt_table_alias + { + Lex->sql_command = SQLCOM_HA_OPEN; + if (!add_table_to_list($2,$4,0)) + YYABORT; + } + | HANDLER_SYM table_ident CLOSE_SYM + { + Lex->sql_command = SQLCOM_HA_CLOSE; + if (!add_table_to_list($2,0,0)) + YYABORT; + } + | HANDLER_SYM table_ident READ_SYM handler_read_or_scan + { + Lex->sql_command = SQLCOM_HA_READ; + if (!add_table_to_list($2,0,0)) + YYABORT; + } + where_clause limit_clause { } + +handler_read_or_scan: + handler_scan_function { Lex->backup_dir= 0; } + | ident handler_rkey_function { Lex->backup_dir= $1.str; } + +handler_scan_function: + FIRST_SYM { Lex->ha_read_mode = RFIRST; } + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + +handler_rkey_function: + FIRST_SYM { Lex->ha_read_mode = RFIRST; } + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + | PREV_SYM { Lex->ha_read_mode = RPREV; } + | LAST_SYM { Lex->ha_read_mode = RLAST; } + | handler_rkey_mode + { + LEX *lex=Lex; + lex->ha_read_mode = RKEY; + if (!(lex->insert_list = new List_item)) + YYABORT; + } '(' values ')' { } + +handler_rkey_mode: + EQ { Lex->ha_rkey_mode=HA_READ_KEY_EXACT; } + | GE { Lex->ha_rkey_mode=HA_READ_KEY_OR_NEXT; } + | LE { Lex->ha_rkey_mode=HA_READ_KEY_OR_PREV; } + | GT_SYM { Lex->ha_rkey_mode=HA_READ_AFTER_KEY; } + | LT { Lex->ha_rkey_mode=HA_READ_BEFORE_KEY; } + /* GRANT / REVOKE */ revoke: REVOKE { - Lex->sql_command = SQLCOM_REVOKE; - Lex->users_list.empty(); - Lex->columns.empty(); - Lex->grant= Lex->grant_tot_col=0; - Lex->db=0; + LEX *lex=Lex; + lex->sql_command = SQLCOM_REVOKE; + lex->users_list.empty(); + lex->columns.empty(); + lex->grant= lex->grant_tot_col=0; + lex->select->db=0; } grant_privileges ON opt_table FROM user_list grant: GRANT { - Lex->sql_command = SQLCOM_GRANT; - Lex->users_list.empty(); - Lex->columns.empty(); - Lex->grant= Lex->grant_tot_col=0; - Lex->db=0; + LEX *lex=Lex; + lex->sql_command = SQLCOM_GRANT; + lex->users_list.empty(); + lex->columns.empty(); + lex->grant= lex->grant_tot_col=0; + lex->select->db=0; } grant_privileges ON opt_table TO_SYM user_list grant_option @@ -2902,43 +3286,47 @@ grant_privilege: opt_table: '*' { - Lex->db=current_thd->db; - if (Lex->grant == UINT_MAX) - Lex->grant = DB_ACLS & ~GRANT_ACL; - else if (Lex->columns.elements) + LEX *lex=Lex; + lex->select->db=lex->thd->db; + if (lex->grant == UINT_MAX) + lex->grant = DB_ACLS & ~GRANT_ACL; + else if (lex->columns.elements) { - net_printf(¤t_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; - } + } } | ident '.' '*' { - Lex->db = $1.str; - if (Lex->grant == UINT_MAX) - Lex->grant = DB_ACLS & ~GRANT_ACL; - else if (Lex->columns.elements) + LEX *lex=Lex; + lex->select->db = $1.str; + if (lex->grant == UINT_MAX) + lex->grant = DB_ACLS & ~GRANT_ACL; + else if (lex->columns.elements) { - net_printf(¤t_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } | '*' '.' '*' { - Lex->db = NULL; - if (Lex->grant == UINT_MAX) - Lex->grant = GLOBAL_ACLS & ~GRANT_ACL; - else if (Lex->columns.elements) + LEX *lex=Lex; + lex->select->db = NULL; + if (lex->grant == UINT_MAX) + lex->grant = GLOBAL_ACLS & ~GRANT_ACL; + else if (lex->columns.elements) { - net_printf(¤t_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } | table_ident { + LEX *lex=Lex; if (!add_table_to_list($1,NULL,0)) YYABORT; - if (Lex->grant == UINT_MAX) - Lex->grant = TABLE_ACLS & ~GRANT_ACL; + if (lex->grant == UINT_MAX) + lex->grant = TABLE_ACLS & ~GRANT_ACL; } @@ -2969,7 +3357,11 @@ grant_user: opt_column_list: - /* empty */ { Lex->grant |= Lex->which_columns; } + /* empty */ + { + LEX *lex=Lex; + lex->grant |= lex->which_columns; + } | '(' column_list ')' column_list: @@ -2982,18 +3374,32 @@ column_list_id: String *new_str = new String((const char*) $1.str,$1.length); List_iterator <LEX_COLUMN> iter(Lex->columns); class LEX_COLUMN *point; + LEX *lex=Lex; while ((point=iter++)) { if (!my_strcasecmp(point->column.ptr(),new_str->ptr())) break; } - Lex->grant_tot_col|= Lex->which_columns; + lex->grant_tot_col|= lex->which_columns; if (point) - point->rights |= Lex->which_columns; + point->rights |= lex->which_columns; else - Lex->columns.push_back(new LEX_COLUMN (*new_str,Lex->which_columns)); + lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns)); } + +require_clause: /* empty */ + | REQUIRE_SYM require_list { /* do magic */} + +require_list: require_list_element AND require_list + { /* do magic */} + | require_list_element {/*do magic*/} + +require_list_element: SUBJECT_SYM TEXT_STRING + | ISSUER TEXT_STRING + | CIPHER TEXT_STRING + + grant_option: /* empty */ {} | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} @@ -3010,3 +3416,32 @@ commit: rollback: ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;} + + +/* +** UNIONS : glue selects together +*/ + + +union: + /* empty */ {} + | union_list + +union_list: + UNION_SYM union_option + { + LEX *lex=Lex; + if (lex->exchange) + { + /* Only the last SELECT can have INTO...... */ + net_printf(¤t_thd->net, ER_WRONG_USAGE,"UNION","INTO"); + YYABORT; + } + mysql_new_select(lex); + lex->select->linkage=UNION_TYPE; + } + SELECT_SYM select_part2 + +union_option: + /* empty */ {} + | ALL {Lex->union_option=1;} diff --git a/sql/structs.h b/sql/structs.h index 36f503312c0..12ba5004a2e 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -125,7 +125,18 @@ typedef struct { enum SHOW_TYPE { SHOW_LONG,SHOW_CHAR,SHOW_INT,SHOW_CHAR_PTR,SHOW_BOOL, SHOW_MY_BOOL,SHOW_OPENTABLES,SHOW_STARTTIME,SHOW_QUESTION, - SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE}; + SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE +#ifdef HAVE_OPENSSL + ,SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD + ,SHOW_SSL_GET_VERSION, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE + ,SHOW_SSL_CTX_SESS_CB_HITS, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE + ,SHOW_SSL_CTX_SESS_NUMBER, SHOW_SSL_SESSION_REUSED + ,SHOW_SSL_CTX_SESS_GET_CACHE_SIZE, SHOW_SSL_GET_CIPHER + ,SHOW_SSL_GET_DEFAULT_TIMEOUT, SHOW_SSL_GET_VERIFY_MODE + ,SHOW_SSL_CTX_GET_VERIFY_MODE, SHOW_SSL_GET_VERIFY_DEPTH + ,SHOW_SSL_CTX_GET_VERIFY_DEPTH +#endif /* HAVE_OPENSSL */ +}; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; @@ -164,3 +175,4 @@ typedef struct st_lex_user { #define STATUS_NOT_READ 8 /* Record isn't read */ #define STATUS_UPDATED 16 /* Record is updated by formula */ #define STATUS_NULL_ROW 32 /* table->null_row is set */ +#define STATUS_DELETED 64 diff --git a/sql/table.h b/sql/table.h index b627a158556..b25e2d82132 100644 --- a/sql/table.h +++ b/sql/table.h @@ -89,7 +89,7 @@ struct st_table { my_bool copy_blobs; /* copy_blobs when storing */ my_bool null_row; /* All columns are null */ my_bool maybe_null,outer_join; /* Used with OUTER JOIN */ - my_bool distinct,const_table; + my_bool distinct,const_table,no_rows; my_bool key_read; my_bool crypted; my_bool db_low_byte_first; /* Portable row format */ @@ -146,3 +146,10 @@ typedef struct st_table_list { bool straight; /* optimize with prev table */ bool updating; /* for replicate-do/ignore table */ } TABLE_LIST; + +typedef struct st_open_table_list +{ + struct st_open_table_list *next; + char *db,*table; + uint32 in_use,locked; +} OPEN_TABLE_LIST; diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index deb304443df..4017b7c30b8 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -22,7 +22,9 @@ extern "C" { void sql_alloc_error_handler(void) { - current_thd->fatal_error=1; /* purecov: inspected */ + THD *thd=current_thd; + if (thd) // QQ; To be removed + thd->fatal_error=1; /* purecov: inspected */ sql_print_error(ER(ER_OUT_OF_RESOURCES)); } } diff --git a/sql/time.cc b/sql/time.cc index e0b74fc9d25..d1e0aee0fa4 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -176,7 +176,9 @@ uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week, ulong first_daynr=calc_daynr(l_time->year,1,1); uint weekday=calc_weekday(first_daynr,sunday_first_day_of_week); *year=l_time->year; - if (l_time->month == 1 && weekday >= 4 && l_time->day <= 7-weekday) + if (l_time->month == 1 && l_time->day <= 7-weekday && + ((!sunday_first_day_of_week && weekday >= 4) || + (sunday_first_day_of_week && weekday != 0))) { /* Last week of the previous year */ if (!with_year) @@ -186,7 +188,8 @@ uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week, first_daynr-= (days=calc_days_in_year(*year)); weekday= (weekday + 53*7- days) % 7; } - if (weekday >= 4) + if ((sunday_first_day_of_week && weekday != 0) || + (!sunday_first_day_of_week && weekday >= 4)) days= daynr - (first_daynr+ (7-weekday)); else days= daynr - (first_daynr - weekday); diff --git a/sql/uniques.cc b/sql/uniques.cc new file mode 100644 index 00000000000..ee1da0f661b --- /dev/null +++ b/sql/uniques.cc @@ -0,0 +1,166 @@ +/* Copyright (C) 2001 MySQL AB + + 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 */ + +/* + Function to handle quick removal of duplicates + This code is used when doing multi-table deletes to find the rows in + reference tables that needs to be deleted. + + The basic idea is as follows: + + Store first all strings in a binary tree, ignoring duplicates. + When the three uses more memory than 'max_heap_table_size', + write the tree (in sorted order) out to disk and start with a new tree. + When all data has been generated, merge the trees (removing any found + duplicates). + + The unique entries will be returned in sort order, to ensure that we do the + deletes in disk order. +*/ + +#include "mysql_priv.h" +#include "sql_sort.h" + + +Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, + uint size, ulong max_in_memory_size_arg) + :max_in_memory_size(max_in_memory_size_arg),elements(0) +{ + my_b_clear(&file); + init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg); + /* If the following fail's the next add will also fail */ + init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); + max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); + open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, + MYF(MY_WME)); +} + + +Unique::~Unique() +{ + close_cached_file(&file); + delete_tree(&tree); + delete_dynamic(&file_ptrs); +} + + + /* Write tree to disk; clear tree */ +bool Unique::flush() +{ + BUFFPEK file_ptr; + elements+= tree.elements_in_tree; + file_ptr.count=tree.elements_in_tree; + file_ptr.file_pos=my_b_tell(&file); + if (tree_walk(&tree, (tree_walk_action) unique_write_to_file, + (void*) this, left_root_right) || + insert_dynamic(&file_ptrs, (gptr) &file_ptr)) + return 1; + delete_tree(&tree); + return 0; +} + + +int unique_write_to_file(gptr key, element_count count, Unique *unique) +{ + return my_b_write(&unique->file, key, unique->tree.size_of_element) ? 1 : 0; +} + +int unique_write_to_ptrs(gptr key, element_count count, Unique *unique) +{ + memcpy(unique->record_pointers, key, unique->tree.size_of_element); + unique->record_pointers+=unique->tree.size_of_element; + return 0; +} + + +/* + Modify the TABLE element so that when one calls init_records() + the rows will be read in priority order. +*/ + +bool Unique::get(TABLE *table) +{ + SORTPARAM sort_param; + table->found_records=elements+tree.elements_in_tree; + + if (my_b_tell(&file) == 0) + { + /* Whole tree is in memory; Don't use disk if you don't need to */ + if ((record_pointers=table->record_pointers= (byte*) + my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0)))) + { + (void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs, + this, left_root_right); + return 0; + } + } + /* Not enough memory; Save the result to file */ + if (flush()) + return 1; + + IO_CACHE *outfile=table->io_cache; + BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer; + uint maxbuffer= file_ptrs.elements - 1; + uchar *sort_buffer; + my_off_t save_pos; + bool error=1; + + /* Open cached file if it isn't open */ + outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + MYF(MY_ZEROFILL)); + + if (!outfile || ! my_b_inited(outfile) && + open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER, + MYF(MY_WME))) + return 1; + reinit_io_cache(outfile,WRITE_CACHE,0L,0,0); + + bzero((char*) &sort_param,sizeof(sort_param)); + sort_param.max_rows= elements; + sort_param.sort_form=table; + sort_param.sort_length=sort_param.ref_length=tree.size_of_element; + sort_param.keys= max_in_memory_size / sort_param.sort_length; + sort_param.not_killable=1; + + if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * + sort_param.sort_length, + MYF(0)))) + return 1; + sort_param.unique_buff= sort_buffer+(sort_param.keys* + sort_param.sort_length); + + /* Merge the buffers to one file, removing duplicates */ + if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file)) + goto err; + if (flush_io_cache(&file) || + reinit_io_cache(&file,READ_CACHE,0L,0,0)) + goto err; + if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr, + file_ptr, file_ptr+maxbuffer,0)) + goto err; + error=0; +err: + x_free((gptr) sort_buffer); + if (flush_io_cache(outfile)) + error=1; + + /* Setup io_cache for reading */ + save_pos=outfile->pos_in_file; + if (reinit_io_cache(outfile,READ_CACHE,0L,0,0)) + error=1; + outfile->end_of_file=save_pos; + return error; +} diff --git a/sql/violite.c b/sql/violite.c deleted file mode 100644 index d551b9b8632..00000000000 --- a/sql/violite.c +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA */ - -/* - Note that we can't have assertion on file descriptors; The reason for - this is that during mysql shutdown, another thread can close a file - we are working on. In this case we should just return read errors from - the file descriptior. -*/ - -#include <global.h> - -#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */ - -#include <errno.h> -#include <assert.h> -#include <violite.h> -#include <my_sys.h> -#include <my_net.h> -#include <m_string.h> -#ifdef HAVE_POLL -#include <sys/poll.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -#if defined(__EMX__) || defined(OS2) -#define ioctlsocket ioctl -#endif /* defined(__EMX__) */ - -#if defined(MSDOS) || defined(__WIN__) -#define O_NONBLOCK 1 /* For emulation of fcntl() */ -#endif -#ifndef EWOULDBLOCK -#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN -#endif - -#ifndef __WIN__ -#define HANDLE void * -#endif - -struct st_vio -{ - my_socket sd; /* my_socket - real or imaginary */ - HANDLE hPipe; - my_bool localhost; /* Are we from localhost? */ - int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ - struct sockaddr_in local; /* Local internet address */ - struct sockaddr_in remote; /* Remote internet address */ - enum enum_vio_type type; /* Type of connection */ - char desc[30]; /* String description */ -}; - -typedef void *vio_ptr; -typedef char *vio_cstring; - -/* - * Helper to fill most of the Vio* with defaults. - */ - -static void vio_reset(Vio* vio, enum enum_vio_type type, - my_socket sd, HANDLE hPipe, - my_bool localhost) -{ - bzero((char*) vio, sizeof(*vio)); - vio->type = type; - vio->sd = sd; - vio->hPipe = hPipe; - vio->localhost= localhost; -} - -/* Open the socket or TCP/IP connection and read the fnctl() status */ - -Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) -{ - Vio *vio; - DBUG_ENTER("vio_new"); - DBUG_PRINT("enter", ("sd=%d", sd)); - if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) - { - vio_reset(vio, type, sd, 0, localhost); - sprintf(vio->desc, - (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"), - vio->sd); -#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) -#if !defined(NO_FCNTL_NONBLOCK) - vio->fcntl_mode = fcntl(sd, F_GETFL); -#elif defined(HAVE_SYS_IOCTL_H) /* hpux */ - /* Non blocking sockets doesn't work good on HPUX 11.0 */ - (void) ioctl(sd,FIOSNBIO,0); -#endif -#else /* !defined(__WIN__) && !defined(__EMX__) */ - { - /* set to blocking mode by default */ - ulong arg=0, r; - r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg)); - } -#endif - } - DBUG_RETURN(vio); -} - - -#ifdef __WIN__ - -Vio *vio_new_win32pipe(HANDLE hPipe) -{ - Vio *vio; - DBUG_ENTER("vio_new_handle"); - if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) - { - vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE); - strmov(vio->desc, "named pipe"); - } - DBUG_RETURN(vio); -} - -#endif - -void vio_delete(Vio * vio) -{ - /* It must be safe to delete null pointers. */ - /* This matches the semantics of C++'s delete operator. */ - if (vio) - { - if (vio->type != VIO_CLOSED) - vio_close(vio); - my_free((gptr) vio,MYF(0)); - } -} - -int vio_errno(Vio *vio __attribute__((unused))) -{ - return socket_errno; /* On Win32 this mapped to WSAGetLastError() */ -} - - -int vio_read(Vio * vio, gptr buf, int size) -{ - int r; - DBUG_ENTER("vio_read"); - DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size)); -#if defined( __WIN__) || defined(OS2) - if (vio->type == VIO_TYPE_NAMEDPIPE) - { - DWORD length; -#ifdef OS2 - if (!DosRead((HFILE)vio->hPipe, buf, size, &length)) - DBUG_RETURN(-1); -#else - if (!ReadFile(vio->hPipe, buf, size, &length, NULL)) - DBUG_RETURN(-1); -#endif - DBUG_RETURN(length); - } - r = recv(vio->sd, buf, size,0); -#else - errno=0; /* For linux */ - r = read(vio->sd, buf, size); -#endif /* __WIN__ */ -#ifndef DBUG_OFF - if (r < 0) - { - DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno)); - } -#endif /* DBUG_OFF */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - - -int vio_write(Vio * vio, const gptr buf, int size) -{ - int r; - DBUG_ENTER("vio_write"); - DBUG_PRINT("enter", ("sd=%d size=%d", vio->sd, size)); -#if defined( __WIN__) || defined(OS2) - if ( vio->type == VIO_TYPE_NAMEDPIPE) - { - DWORD length; -#ifdef OS2 - if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length)) - DBUG_RETURN(-1); -#else - if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL)) - DBUG_RETURN(-1); -#endif - DBUG_RETURN(length); - } - r = send(vio->sd, buf, size,0); -#else - r = write(vio->sd, buf, size); -#endif /* __WIN__ */ -#ifndef DBUG_OFF - if (r < 0) - { - DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno)); - } -#endif /* DBUG_OFF */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - - -int vio_blocking(Vio * vio, my_bool set_blocking_mode) -{ - int r=0; - DBUG_ENTER("vio_blocking"); - DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode)); - -#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) -#if !defined(NO_FCNTL_NONBLOCK) - - if (vio->sd >= 0) - { - int old_fcntl=vio->fcntl_mode; - if (set_blocking_mode) - vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */ - else - vio->fcntl_mode |= O_NONBLOCK; /* set bit */ - if (old_fcntl != vio->fcntl_mode) - r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode); - } -#endif /* !defined(NO_FCNTL_NONBLOCK) */ -#else /* !defined(__WIN__) && !defined(__EMX__) */ -#ifndef __EMX__ - if (vio->type != VIO_TYPE_NAMEDPIPE) -#endif - { - ulong arg; - int old_fcntl=vio->fcntl_mode; - if (set_blocking_mode) - { - arg = 0; - vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */ - } - else - { - arg = 1; - vio->fcntl_mode |= O_NONBLOCK; /* set bit */ - } - if (old_fcntl != vio->fcntl_mode) - r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg)); - } -#endif /* !defined(__WIN__) && !defined(__EMX__) */ - DBUG_RETURN(r); -} - -my_bool -vio_is_blocking(Vio * vio) -{ - my_bool r; - DBUG_ENTER("vio_is_blocking"); - r = !(vio->fcntl_mode & O_NONBLOCK); - DBUG_PRINT("exit", ("%d", (int) r)); - DBUG_RETURN(r); -} - - -int vio_fastsend(Vio * vio __attribute__((unused))) -{ - int r=0; - DBUG_ENTER("vio_fastsend"); - -#ifdef IPTOS_THROUGHPUT - { -#ifndef __EMX__ - int tos = IPTOS_THROUGHPUT; - if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos))) -#endif /* !__EMX__ */ - { - int nodelay = 1; - if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay, - sizeof(nodelay))) { - DBUG_PRINT("warning", - ("Couldn't set socket option for fast send")); - r= -1; - } - } - } -#endif /* IPTOS_THROUGHPUT */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - -int vio_keepalive(Vio* vio, my_bool set_keep_alive) -{ - int r=0; - uint opt = 0; - DBUG_ENTER("vio_keepalive"); - DBUG_PRINT("enter", ("sd=%d set_keep_alive=%d", vio->sd, (int) - set_keep_alive)); - if (vio->type != VIO_TYPE_NAMEDPIPE) - { - if (set_keep_alive) - opt = 1; - r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, - sizeof(opt)); - } - DBUG_RETURN(r); -} - - -my_bool -vio_should_retry(Vio * vio __attribute__((unused))) -{ - int en = socket_errno; - return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK; -} - - -int vio_close(Vio * vio) -{ - int r; - DBUG_ENTER("vio_close"); -#ifdef __WIN__ - if (vio->type == VIO_TYPE_NAMEDPIPE) - { -#if defined(__NT__) && defined(MYSQL_SERVER) - CancelIo(vio->hPipe); - DisconnectNamedPipe(vio->hPipe); -#endif - r=CloseHandle(vio->hPipe); - } - else if (vio->type != VIO_CLOSED) -#endif /* __WIN__ */ - { - r=0; - if (shutdown(vio->sd,2)) - r= -1; - if (closesocket(vio->sd)) - r= -1; - } - if (r) - { - DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno)); - /* FIXME: error handling (not critical for MySQL) */ - } - vio->type= VIO_CLOSED; - vio->sd= -1; - DBUG_RETURN(r); -} - - -const char *vio_description(Vio * vio) -{ - return vio->desc; -} - -enum enum_vio_type vio_type(Vio* vio) -{ - return vio->type; -} - -my_socket vio_fd(Vio* vio) -{ - return vio->sd; -} - - -my_bool vio_peer_addr(Vio * vio, char *buf) -{ - DBUG_ENTER("vio_peer_addr"); - DBUG_PRINT("enter", ("sd=%d", vio->sd)); - if (vio->localhost) - { - strmov(buf,"127.0.0.1"); - } - else - { - size_socket addrLen = sizeof(struct sockaddr); - if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)), - &addrLen) != 0) - { - DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno)); - DBUG_RETURN(1); - } - my_inet_ntoa(vio->remote.sin_addr,buf); - } - DBUG_PRINT("exit", ("addr=%s", buf)); - DBUG_RETURN(0); -} - - -void vio_in_addr(Vio *vio, struct in_addr *in) -{ - DBUG_ENTER("vio_in_addr"); - if (vio->localhost) - bzero((char*) in, sizeof(*in)); /* This should never be executed */ - else - *in=vio->remote.sin_addr; - DBUG_VOID_RETURN; -} - - -/* Return 0 if there is data to be read */ - -my_bool vio_poll_read(Vio *vio,uint timeout) -{ -#ifndef HAVE_POLL - return 0; -#else - struct pollfd fds; - int res; - DBUG_ENTER("vio_poll"); - fds.fd=vio->sd; - fds.events=POLLIN; - fds.revents=0; - if ((res=poll(&fds,1,(int) timeout*1000)) <= 0) - { - DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */ - } - DBUG_RETURN(fds.revents & POLLIN ? 0 : 1); -#endif -} - -#endif /* HAVE_VIO */ diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c new file mode 100644 index 00000000000..a0a9686e0c1 --- /dev/null +++ b/strings/ctype-latin1_de.c @@ -0,0 +1,356 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + +/* + * This file is the latin1 character set with German sorting + * + * The modern sort order is used, where: + * + * 'ä' -> "ae" + * 'ö' -> "oe" + * 'ü' -> "ue" + * 'ß' -> "ss" + */ + +/* + * This comment is parsed by configure to create ctype.c, + * so don't change it unless you know what you are doing. + * + * .configure. strxfrm_multiply_latin1_de=2 + */ + +#include <global.h> +#include "m_string.h" +#include "m_ctype.h" + +uchar ctype_latin1_de[] = { + 0, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 132,132,132,132,132,132,132,132,132,132, 16, 16, 16, 16, 16, 16, + 16,129,129,129,129,129,129, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, + 16,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2 +}; + +uchar to_lower_latin1_de[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,215,248,249,250,251,252,253,254,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +uchar to_upper_latin1_de[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255 +}; + +/* + * This is a simple latin1 mapping table, which maps all accented + * characters to their non-accented equivalents. Note: in this + * table, 'ä' is mapped to 'A', 'ÿ' is mapped to 'Y', etc. - all + * accented characters except the following are treated the same way. + * Ü, ü, É, é, Ö, ö, Ä, ä + */ + +uchar sort_order_latin1_de[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 65, 65, 65, 65,196, 65, 92, 67, 69,201, 69, 69, 73, 73, 73, 73, + 68, 78, 79, 79, 79, 79,214,215,216, 85, 85, 85,220, 89,222,223, + 65, 65, 65, 65,196, 65, 92, 67, 69,201, 69, 69, 73, 73, 73, 73, + 68, 78, 79, 79, 79, 79,214,247,216, 85, 85, 85,220, 89,222, 89 +}; + +#define L1_AE 196 +#define L1_ae 228 +#define L1_OE 214 +#define L1_oe 246 +#define L1_UE 220 +#define L1_ue 252 +#define L1_ss 223 + + +/* + Some notes about the following comparison rules: + By definition, my_strnncoll_latin_de must works exactly as if had called + my_strnxfrm_latin_de() on both strings and compared the result strings. + + This means that: + Ä must also matches ÁE and Aè, because my_strxn_frm_latin_de() will convert + both to AE. + + The other option would be to not do any accent removal in + sort_order_latin_de[] at all +*/ + + +#define CHECK_S1_COMBO(ch1, ch2, str1, str1_end, res_if_str1_smaller, str2, fst, snd, accent) \ + /* Invariant: ch1 == fst == sort_order_latin1_de[accent] && ch1 != ch2 */ \ + if (ch2 != accent) \ + { \ + ch1= fst; \ + goto normal; \ + } \ + if (str1 == str1_end) \ + return res_if_str1_smaller; \ + { \ + int diff = (int) sort_order_latin1_de[*str1] - snd; \ + if (diff) \ + return diff*(-(res_if_str1_smaller)); \ + /* They are equal (e.g., "Ae" == 'ä') */ \ + str1++; \ + } + + +int my_strnncoll_latin1_de(const uchar * s1, int len1, + const uchar * s2, int len2) +{ + const uchar *e1 = s1 + len1; + const uchar *e2 = s2 + len2; + + while (s1 < e1 && s2 < e2) + { + /* + Because sort_order_latin1_de doesn't convert 'Ä', Ü or ß we + can use it here. + */ + uchar c1 = sort_order_latin1_de[*s1++]; + uchar c2 = sort_order_latin1_de[*s2++]; + if (c1 != c2) + { + switch (c1) { + case 'A': + CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'A', 'E', L1_AE); + break; + case 'O': + CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'O', 'E', L1_OE); + break; + case 'U': + CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'U', 'E', L1_UE); + break; + case 'S': + CHECK_S1_COMBO(c1, c2, s1, e1, -1, s2, 'S', 'S', L1_ss); + break; + case L1_AE: + CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'A', 'E', 'A'); + break; + case L1_OE: + CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'O', 'E', 'O'); + break; + case L1_UE: + CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'U', 'E', 'U'); + break; + case L1_ss: + CHECK_S1_COMBO(c1, c2, s2, e2, 1, s1, 'S', 'S', 'S'); + break; + default: + /* + Handle the case where 'c2' is a special character + If this is true, we know that c1 can't match this character. + */ + normal: + switch (c2) { + case L1_AE: + return (int) c1 - (int) 'A'; + case L1_OE: + return (int) c1 - (int) 'O'; + case L1_UE: + return (int) c1 - (int) 'U'; + case L1_ss: + return (int) c1 - (int) 'S'; + default: + { + int diff= (int) c1 - (int) c2; + if (diff) + return diff; + } + break; + } + } + } + } + /* A simple test of string lengths won't work -- we test to see + * which string ran out first */ + return s1 < e1 ? 1 : s2 < e2 ? -1 : 0; +} + + +int my_strnxfrm_latin1_de(uchar * dest, const uchar * src, int len, int srclen) +{ + const uchar *dest_orig = dest; + const uchar *de = dest + len; + const uchar *se = src + srclen; + while (src < se && dest < de) + { + uchar chr=sort_order_latin1_de[*src]; + switch (chr) { + case L1_AE: + *dest++ = 'A'; + if (dest < de) + *dest++ = 'E'; + break; + case L1_OE: + *dest++ = 'O'; + if (dest < de) + *dest++ = 'E'; + break; + case L1_UE: + *dest++ = 'U'; + if (dest < de) + *dest++ = 'E'; + break; + case L1_ss: + *dest++ = 'S'; + if (dest < de) + *dest++ = 'S'; + break; + default: + *dest++= chr; + break; + } + ++src; + } + return dest - dest_orig; +} + + +int my_strcoll_latin1_de(const uchar * s1, const uchar * s2) +{ + /* XXX QQ: This should be fixed to not call strlen */ + return my_strnncoll_latin1_de(s1, strlen(s1), s2, strlen(s2)); +} + +int my_strxfrm_latin1_de(uchar * dest, const uchar * src, int len) +{ + /* XXX QQ: This should be fixed to not call strlen */ + return my_strnxfrm_latin1_de(dest, src, len, strlen(src)); +} + +/* + * Calculate min_str and max_str that ranges a LIKE string. + * Arguments: + * ptr IN: Pointer to LIKE string. + * ptr_length IN: Length of LIKE string. + * escape IN: Escape character in LIKE. (Normally '\'). + * No escape characters should appear in min_str or max_str + * res_length IN: Length of min_str and max_str. + * min_str IN/OUT: Smallest case sensitive string that ranges LIKE. + * Should be space padded to res_length. + * max_str IN/OUT: Largest case sensitive string that ranges LIKE. + * Normally padded with the biggest character sort value. + * min_length OUT: Length of min_str without space padding. + * max_length OUT: Length of max_str without space padding. + * + * The function should return 0 if ok and 1 if the LIKE string can't be + * optimized ! + */ + +#define min_sort_char ((char) 0) +#define max_sort_char ((char) 255) +#define wild_one '_' +#define wild_many '%' + +my_bool my_like_range_latin1_de(const char *ptr, uint ptr_length, + pchar escape, uint res_length, + char *min_str, char *max_str, + uint *min_length, uint *max_length) +{ + const char *end = ptr + ptr_length; + char *min_org = min_str; + char *min_end = min_str + res_length; + + for (; ptr != end && min_str != min_end; ++ptr) + { + if (*ptr == escape && ptr + 1 != end) + { + ++ptr; /* Skip escape */ + *min_str++ = *max_str++ = *ptr; + continue; + } + if (*ptr == wild_one) /* '_' in SQL */ + { + *min_str++ = min_sort_char; + *max_str++ = max_sort_char; + continue; + } + if (*ptr == wild_many) /* '%' in SQL */ + { + *min_length = (uint)(min_str - min_org); + *max_length = res_length; + do { + *min_str++ = min_sort_char; + *max_str++ = max_sort_char; + } while (min_str != min_end); + return 0; + } + *min_str++ = *max_str++ = *ptr; + } + *min_length = *max_length = (uint) (min_str - min_org); + while (min_str != min_end) + { + *min_str++ = ' '; /* For proper key compression */ + *max_str++ = ' '; + } + return 0; +} diff --git a/strings/ctype.c b/strings/ctype.c index d6f02ec5054..a0e183a89d6 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -18,6 +18,7 @@ #include <global.h> #include <m_ctype.h> +#include <m_string.h> /* generated by make, using conf_to_src */ #include "ctype_extra_sources.c" diff --git a/support-files/binary-configure.sh b/support-files/binary-configure.sh index 682ea570b25..107f468bffc 100644 --- a/support-files/binary-configure.sh +++ b/support-files/binary-configure.sh @@ -20,5 +20,5 @@ then echo "Starting the mysqld server. You can test that it is up and running" echo "with the command:" echo "./bin/mysqladmin version" - ./bin/safe_mysqld & + ./bin/mysqld_safe & fi diff --git a/support-files/mysql-max.spec.sh b/support-files/mysql-max.spec.sh index 49f131154c0..5c4b16f0e9d 100644 --- a/support-files/mysql-max.spec.sh +++ b/support-files/mysql-max.spec.sh @@ -208,7 +208,7 @@ chmod -R og-rw $mysql_datadir/mysql # Restart in the same way that mysqld will be started normally. /etc/rc.d/init.d/mysql start -# Allow safe_mysqld to start mysqld and print a message before we exit +# Allow mysqld_safe to start mysqld and print a message before we exit sleep 2 %preun @@ -244,7 +244,7 @@ fi %attr(755, root, root) /usr/bin/perror %attr(755, root, root) /usr/bin/replace %attr(755, root, root) /usr/bin/resolveip -%attr(755, root, root) /usr/bin/safe_mysqld +%attr(755, root, root) /usr/bin/mysqld_safe %attr(755, root, root) /usr/bin/mysqld_multi %attr(755, root, root) /usr/bin/my_print_defaults diff --git a/support-files/mysql-multi.server.sh b/support-files/mysql-multi.server.sh index 6c940630427..31020029354 100644 --- a/support-files/mysql-multi.server.sh +++ b/support-files/mysql-multi.server.sh @@ -133,14 +133,14 @@ case "$mode" in 'start') # Start daemon - if test -x $bindir/safe_mysqld + if test -x $bindir/mysqld_safe then # We only need to specify datadir and pid-file here and we # get all other instance-specific config from $datadir/my.cnf. # We have to explicitly pass --defaults-extra-file because it # reads the config files before the command line options. - # Also it must be first because of the way safe_mysqld works. - $bindir/safe_mysqld --defaults-extra-file=$datadir/my.cnf \ + # Also it must be first because of the way mysqld_safe works. + $bindir/mysqld_safe --defaults-extra-file=$datadir/my.cnf \ --datadir=$datadir --pid-file=$pid_file & # Make lock for RedHat / SuSE if test -d /var/lock/subsys @@ -148,7 +148,7 @@ case "$mode" in touch /var/lock/subsys/mysql fi else - echo "Can't execute $bindir/safe_mysqld" + echo "Can't execute $bindir/mysqld_safe" fi ;; diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 62381ccf0d3..ee5a9adaf8b 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -100,18 +100,18 @@ case "$mode" in 'start') # Start daemon - if test -x $bindir/safe_mysqld + if test -x $bindir/mysqld_safe then # Give extra arguments to mysqld with the my.cnf file. This script may # be overwritten at next upgrade. - $bindir/safe_mysqld --datadir=$datadir --pid-file=$pid_file & + $bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file & # Make lock for RedHat / SuSE if test -w /var/lock/subsys then touch /var/lock/subsys/mysql fi else - echo "Can't execute $bindir/safe_mysqld" + echo "Can't execute $bindir/mysqld_safe" fi ;; diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 3245908c9b0..f5ce41a1c70 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -302,7 +302,7 @@ chmod -R og-rw $mysql_datadir/mysql # Restart in the same way that mysqld will be started normally. /etc/rc.d/init.d/mysql start -# Allow safe_mysqld to start mysqld and print a message before we exit +# Allow mysqld_safe to start mysqld and print a message before we exit sleep 2 %post Max @@ -348,7 +348,7 @@ fi %attr(755, root, root) /usr/bin/perror %attr(755, root, root) /usr/bin/replace %attr(755, root, root) /usr/bin/resolveip -%attr(755, root, root) /usr/bin/safe_mysqld +%attr(755, root, root) /usr/bin/mysqld_safe %attr(755, root, root) /usr/bin/mysqld_multi %attr(755, root, root) /usr/bin/my_print_defaults @@ -386,7 +386,7 @@ fi %attr(644, root, man) %doc /usr/man/man1/mysqlshow.1* %attr(644, root, man) %doc /usr/man/man1/perror.1* %attr(644, root, man) %doc /usr/man/man1/replace.1* -%attr(644, root, man) %doc /usr/man/man1/safe_mysqld.1* +%attr(644, root, man) %doc /usr/man/man1/mysqld_safe.1* %post shared /sbin/ldconfig diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000000..aa513c13f05 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(srcdir)/../include $(openssl_includes) \ + -I../include -I$(srcdir)/.. -I$(top_srcdir) \ + -I.. +LIBS = @TOOLS_LIBS@ $(openssl_libs) +LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql_r/libmysqlclient_r.la +bin_PROGRAMS = mysqlmanager +mysqlmanager_SOURCES = mysqlmanager.c +mysqlmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) +DEFS = -DUNDEF_THREADS_HACK + +# Don't update the files from bitkeeper +%::SCCS/s.% + + diff --git a/tools/managertest1.nc b/tools/managertest1.nc new file mode 100644 index 00000000000..1125e141588 --- /dev/null +++ b/tools/managertest1.nc @@ -0,0 +1,12 @@ +root secret +def_exec server /usr/sbin/mysqld --socket=/tmp/temp.sock --skip-grant --skip-net --datadir=/tmp +set_exec_con server root localhost /tmp/temp.sock +start_exec server 3 +show_exec +stop_exec server 3 +show_exec +start_exec server 3 +show_exec +stop_exec server 3 +show_exec +shutdown diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c new file mode 100644 index 00000000000..3572dde67d3 --- /dev/null +++ b/tools/mysqlmanager.c @@ -0,0 +1,1565 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + +/* MySQL server management daemon + * + * Written by: + * Sasha Pachev <sasha@mysql.com> + **/ + +#include <global.h> +#include <my_sys.h> +#include <m_string.h> +#include <mysql.h> +#include <mysql_version.h> +#include <m_ctype.h> +#include <my_config.h> +#include <my_dir.h> +#include <hash.h> +#include <mysqld_error.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <errno.h> +#include <violite.h> +#include <my_pthread.h> + +#define MANAGER_VERSION "1.0" +#define MANAGER_GREETING "MySQL Server Management Daemon v." ## \ + MANAGER_VERSION + +#define LOG_ERR 1 +#define LOG_WARN 2 +#define LOG_INFO 3 +#define LOG_DEBUG 4 + +#define CHILD_START 1 +#define CHILD_STOP 2 + +#ifndef MANAGER_PORT +#define MANAGER_PORT 23546 +#endif + +#ifndef MANAGER_CONNECT_RETRIES +#define MANAGER_CONNECT_RETRIES 5 +#endif + +#ifndef MANAGER_MAX_CMD_LEN +#define MANAGER_MAX_CMD_LEN 16384 +#endif + +#ifndef MANAGER_LOG_FILE +#define MANAGER_LOG_FILE "/var/log/mysqlmanager.log" +#endif + +#ifndef MANAGER_BACK_LOG +#define MANAGER_BACK_LOG 50 +#endif + +#ifndef MAX_USER_NAME +#define MAX_USER_NAME 16 +#endif + +#ifndef MANAGER_PW_FILE +#define MANAGER_PW_FILE "/etc/mysqlmanager.passwd" +#endif + +#ifndef MAX_HOST +#define MAX_HOST 128 +#endif + +#ifndef MAX_LAUNCHER_MSG +#define MAX_LAUNCHER_MSG 256 +#endif + +/* Variable naming convention - if starts with manager_, either is set + directly by the user, or used closely in ocnjunction with a variable + set by the user +*/ + +#if defined(__i386__) && defined(HAVE_LINUXTHREADS) +#define DO_STACKTRACE 1 +#endif + +uint manager_port = MANAGER_PORT; +FILE* errfp; +const char* manager_log_file = MANAGER_LOG_FILE; +pthread_mutex_t lock_log,lock_shutdown,lock_exec_hash,lock_launch_thd; +pthread_cond_t cond_launch_thd; +pthread_t loop_th,launch_msg_th; +int manager_sock = -1; +uchar* stack_bottom=0; +struct sockaddr_in manager_addr; +ulong manager_bind_addr = INADDR_ANY; +int manager_back_log = MANAGER_BACK_LOG; +int in_shutdown = 0, shutdown_requested=0; +int manager_connect_retries=MANAGER_CONNECT_RETRIES; +const char* manager_greeting = MANAGER_GREETING; +uint manager_max_cmd_len = MANAGER_MAX_CMD_LEN; +const char* manager_pw_file=MANAGER_PW_FILE; +int one_thread = 0; /* for debugging */ + +/* messages */ + +#define MAX_CLIENT_MSG_LEN 256 +#define NET_BLOCK 2048 +#define MD5_LEN 32 +#define ESCAPE_CHAR '\\' +#define EOL_CHAR '\n' + +#define MSG_OK 200 +#define MSG_INFO 250 +#define MSG_ACCESS 401 +#define MSG_CLIENT_ERR 450 +#define MSG_INTERNAL_ERR 500 + +/* access flags */ + +#define PRIV_SHUTDOWN 1 + +struct manager_thd +{ + Vio* vio; + char user[MAX_USER_NAME]; + int priv_flags; + char* cmd_buf; + int fatal,finished; +}; + +struct manager_user +{ + char user[MAX_USER_NAME]; + char md5_pass[MD5_LEN]; + int user_len; + const char* error; +}; + +HASH exec_hash,user_hash; +struct manager_exec* cur_launch_exec=0; + +static struct manager_thd* manager_thd_new(Vio* vio); + +static struct manager_exec* manager_exec_new(char* arg_start,char* arg_end); +static void manager_exec_print(Vio* vio,struct manager_exec* e); +static void manager_thd_free(struct manager_thd* thd); +static void manager_exec_free(void* e); +static void manager_exec_connect(struct manager_exec* e); +static int manager_exec_launch(struct manager_exec* e); +static struct manager_exec* manager_exec_by_pid(pid_t pid); + +static struct manager_user* manager_user_new(char* buf); +static void manager_user_free(void* u); + +static char* arg_strmov(char* dest, const char* src, int n); +static byte* get_exec_key(const byte* e, uint* len, + my_bool __attribute__((unused)) t); +static byte* get_user_key(const byte* u, uint* len, + my_bool __attribute__((unused)) t); +static uint tokenize_args(char* arg_start,char** arg_end); +static void init_arg_array(char* arg_str,char** args,uint arg_count); + +typedef int (*manager_cmd_handler)(struct manager_thd*,char*,char*); + +static void handle_child(int __attribute__((unused)) sig); +static void handle_sigpipe(int __attribute__((unused)) sig); + +/* exec() in a threaded application is full of problems + to solve this, we fork off a launcher at the very start + and communicate with it through a pipe +*/ +static void fork_launcher(); +static void run_launcher_loop(); +int to_launcher_pipe[2],from_launcher_pipe[2]; +pid_t launcher_pid; +int in_segfault=0; + +struct manager_cmd +{ + const char* name; + const char* help; + manager_cmd_handler handler_func; + int len; +}; + +struct manager_exec +{ + char* ident; + int ident_len; + const char* error; + char* bin_path; + char** args; + char con_user[16]; + char con_pass[16]; + int con_port; + pid_t pid; + int exit_code; + pthread_mutex_t lock; + pthread_cond_t cond; + pthread_t th; + char con_sock[FN_REFLEN]; + char con_host[MAX_HOST]; + MYSQL mysql; + char* data_buf; + int req_len; + int num_args; +}; + +#define HANDLE_DECL(com) static int handle_ ## com (struct manager_thd* thd,\ + char* args_start,char* args_end) + +#define HANDLE_NOARG_DECL(com) static int handle_ ## com \ + (struct manager_thd* thd, char* __attribute__((unused)) args_start,\ + char* __attribute__((unused)) args_end) + + +HANDLE_NOARG_DECL(ping); +HANDLE_NOARG_DECL(quit); +HANDLE_NOARG_DECL(help); +HANDLE_NOARG_DECL(shutdown); +HANDLE_DECL(def_exec); +HANDLE_DECL(start_exec); +HANDLE_DECL(stop_exec); +HANDLE_DECL(set_exec_con); +HANDLE_NOARG_DECL(show_exec); + +struct manager_cmd commands[] = +{ + {"ping", "Check if this server is alive", handle_ping,4}, + {"quit", "Finish session", handle_quit,4}, + {"shutdown", "Shutdown this server", handle_shutdown,8}, + {"def_exec", "Define executable entry", handle_def_exec,8}, + {"start_exec", "Launch process defined by executable entry", + handle_start_exec,10}, + {"stop_exec", "Stop process defined by executable entry", + handle_stop_exec,9}, + {"set_exec_con", "Set connection parameters for executable entry", + handle_set_exec_con,12}, + {"show_exec","Show defined executable entries",handle_show_exec,9}, + {"help", "Print this message", handle_help,4}, + {0,0,0,0} +}; + +struct option long_options[] = +{ + {"debug", optional_argument, 0, '#'}, + {"help", no_argument, 0, 'h'}, + {"port", required_argument, 0, 'P'}, + {"log", required_argument, 0, 'l'}, + {"bind-address", required_argument, 0, 'b'}, + {"tcp-backlog", required_argument, 0, 'B'}, + {"greeting", required_argument, 0, 'g'}, + {"max-command-len",required_argument,0,'m'}, + {"one-thread",no_argument,0,'d'}, + {"connect-retries",required_argument,0,'C'}, + {"password-file",required_argument,0,'p'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0} +}; + +static void die(const char* fmt,...); +static void print_time(FILE* fp); +static void clean_up(); +static struct manager_cmd* lookup_cmd(char* s,int len); +static void client_msg(Vio* vio,int err_code,const char* fmt,...); +static void client_msg_pre(Vio* vio,int err_code,const char* fmt,...); +static void client_msg_raw(Vio* vio,int err_code,int pre,const char* fmt, + va_list args); +static int authenticate(struct manager_thd* thd); +static char* read_line(struct manager_thd* thd); /* returns pointer to end of + line + */ +static pthread_handler_decl(process_connection,arg); +static pthread_handler_decl(process_launcher_messages, + __attribute__((unused)) arg); +static int exec_line(struct manager_thd* thd,char* buf,char* buf_end); + +#ifdef DO_STACKTRACE +void print_stacktrace(); +#endif + +static void handle_segfault(int sig) +{ + if (in_segfault) + exit(1); + in_segfault=1; + fprintf(errfp,"Got fatal signal %d\n",sig); +#ifdef DO_STACKTRACE + print_stacktrace(); +#endif + exit(1); +} + +static void handle_sigpipe(int __attribute__((unused)) sig) +{ + signal(SIGPIPE,handle_sigpipe); +} + +#ifdef DO_STACKTRACE + +#define MAX_DEPTH 25 +#define SIGRETURN_FRAME_COUNT 1 + +void print_stacktrace() +{ + uchar** fp; + int i; + LINT_INIT(fp); + fprintf(errfp,"Fatal errror, stacktrace follows:\n"); +#ifdef __i386__ + __asm__ __volatile__("movl %%ebp,%0" :"=r"(fp) :"r"(fp)); +#endif + if (!fp) + { + fprintf(errfp,"frame points is NULL, cannot trace stack\n"); + return; + } + for(i=0;i<MAX_DEPTH && fp<(uchar**)stack_bottom;i++) + { +#ifdef __i386__ + uchar** new_fp = (uchar**)*fp; + fprintf(errfp, "%p\n", i == SIGRETURN_FRAME_COUNT ? + *(fp+17) : *(fp+1)); +#endif /* __386__ */ + if (new_fp <= fp ) + { + fprintf(errfp, "New value of fp=%p failed sanity check,\ + terminating stack trace!\n", new_fp); + return; + } + fp = new_fp; + } + fprintf(errfp,"Stack trace successful\n"); + fflush(errfp); +} +#endif + +static int exec_line(struct manager_thd* thd,char* buf,char* buf_end) +{ + char* p=buf; + struct manager_cmd* cmd; + for (;p<buf_end && !isspace(*p);p++) + *p=tolower(*p); + if (!(cmd=lookup_cmd(buf,(int)(p-buf)))) + { + client_msg(thd->vio,MSG_CLIENT_ERR, + "Unrecognized command, type help to see list of supported\ + commands"); + return 1; + } + for (;p<buf_end && isspace(*p);p++); + return cmd->handler_func(thd,p,buf_end); +} + +static struct manager_cmd* lookup_cmd(char* s,int len) +{ + struct manager_cmd* cmd = commands; + for (;cmd->name;cmd++) + { + if (cmd->len == len && !memcmp(cmd->name,s,len)) + return cmd; + } + return 0; +} + +HANDLE_NOARG_DECL(ping) +{ + client_msg(thd->vio,MSG_OK,"Server management daemon is alive"); + return 0; +} + +HANDLE_NOARG_DECL(quit) +{ + client_msg(thd->vio,MSG_OK,"Goodbye"); + thd->finished=1; + return 0; +} + +HANDLE_NOARG_DECL(help) +{ + struct manager_cmd* cmd = commands; + Vio* vio = thd->vio; + client_msg_pre(vio,MSG_INFO,"Available commands:"); + for (;cmd->name;cmd++) + { + client_msg_pre(vio,MSG_INFO,"%s - %s", cmd->name, cmd->help); + } + client_msg_pre(vio,MSG_INFO,"End of help"); + return 0; +} + +HANDLE_NOARG_DECL(shutdown) +{ + client_msg(thd->vio,MSG_OK,"Shutdown started, goodbye"); + thd->finished=1; + shutdown_requested = 1; + if (!one_thread) + { + kill(launcher_pid,SIGTERM); + pthread_kill(loop_th,SIGTERM); + } + return 0; +} + +HANDLE_DECL(set_exec_con) +{ + int num_args; + const char* error=0; + struct manager_exec* e; + char* arg_p; + if ((num_args=tokenize_args(args_start,&args_end))<2) + { + error="Too few arguments"; + goto err; + } + arg_p=args_start; + pthread_mutex_lock(&lock_exec_hash); + if (!(e=(struct manager_exec*)hash_search(&exec_hash,arg_p, + strlen(arg_p)))) + { + pthread_mutex_unlock(&lock_exec_hash); + error="Exec definition entry does not exist"; + goto err; + } + arg_p+=strlen(arg_p)+1; + arg_p+=(strnmov(e->con_user,arg_p,sizeof(e->con_user))-e->con_user)+1; + if (num_args >= 3) + { + arg_p+=(strnmov(e->con_host,arg_p,sizeof(e->con_host))-e->con_host)+1; + if (num_args == 4) + { + if (!(e->con_port=atoi(arg_p))) + strnmov(e->con_sock,arg_p,sizeof(e->con_sock)); + else + e->con_sock[0]=0; + } + else + { + pthread_mutex_unlock(&lock_exec_hash); + error="Too many arguments"; + goto err; + } + } + pthread_mutex_unlock(&lock_exec_hash); + client_msg(thd->vio,MSG_OK,"Entry updated"); + return 0; +err: + client_msg(thd->vio,MSG_CLIENT_ERR,error); + return 1; +} + +HANDLE_DECL(start_exec) +{ + int num_args; + struct manager_exec* e; + int ident_len; + const char* error=0; + struct timespec t; + if ((num_args=tokenize_args(args_start,&args_end))<1) + { + error="Too few arguments"; + goto err; + } + ident_len=strlen(args_start); + pthread_mutex_lock(&lock_exec_hash); + if (!(e=(struct manager_exec*)hash_search(&exec_hash,args_start, + ident_len))) + { + pthread_mutex_unlock(&lock_exec_hash); + error="Exec definition entry does not exist"; + goto err; + } + pthread_mutex_unlock(&lock_exec_hash); + manager_exec_launch(e); + if ((error=e->error)) + goto err; + pthread_mutex_lock(&e->lock); + t.tv_sec=time(0)+atoi(args_start+ident_len+1); + t.tv_nsec=0; + pthread_cond_timedwait(&e->cond,&e->lock,&t); + if (!e->pid) + { + pthread_mutex_unlock(&e->lock); + error="Process failed to start withing alotted time"; + goto err; + } + mysql_close(&e->mysql); + manager_exec_connect(e); + error=e->error; + pthread_mutex_unlock(&e->lock); + if (error) + goto err; + client_msg(thd->vio,MSG_OK,"'%s' started",e->ident); + return 0; +err: + client_msg(thd->vio,MSG_CLIENT_ERR,error); + return 1; +} + +HANDLE_DECL(stop_exec) +{ + int num_args; + struct timespec abstime; + struct manager_exec* e; + int ident_len; + const char* error=0; + if ((num_args=tokenize_args(args_start,&args_end))<2) + { + error="Too few arguments"; + goto err; + } + ident_len=strlen(args_start); + abstime.tv_sec=time(0)+atoi(args_start+1+ident_len); + abstime.tv_nsec=0; + pthread_mutex_lock(&lock_exec_hash); + if (!(e=(struct manager_exec*)hash_search(&exec_hash,args_start, + ident_len))) + { + pthread_mutex_unlock(&lock_exec_hash); + error="Exec definition entry does not exist"; + goto err; + } + pthread_mutex_unlock(&lock_exec_hash); + pthread_mutex_lock(&e->lock); + e->th=pthread_self(); + if (!e->pid) + { + e->th=0; + pthread_mutex_unlock(&e->lock); + error="Process not running"; + goto err; + } + if (mysql_shutdown(&e->mysql)) + { + e->th=0; + pthread_mutex_unlock(&e->lock); + error="Could not send shutdown command"; + goto err; + } + pthread_cond_timedwait(&e->cond,&e->lock,&abstime); + if (e->pid) + error="Process failed to terminate within alotted time"; + e->th=0; + pthread_mutex_unlock(&e->lock); + if (!error) + { + client_msg(thd->vio,MSG_OK,"'%s' terminated",e->ident); + return 0; + } +err: + client_msg(thd->vio,MSG_CLIENT_ERR,error); + return 1; +} + +HANDLE_DECL(def_exec) +{ + struct manager_exec* e=0,*old_e; + const char* error=0; + if (!(e=manager_exec_new(args_start,args_end))) + { + error="Out of memory"; + goto err; + } + if (e->error) + { + error=e->error; + goto err; + } + pthread_mutex_lock(&lock_exec_hash); + if ((old_e=(struct manager_exec*)hash_search(&exec_hash,(byte*)e->ident, + e->ident_len))) + { + pthread_mutex_unlock(&lock_exec_hash); + error="Exec definition already exists"; + goto err; + } + hash_insert(&exec_hash,(byte*)e); + pthread_mutex_unlock(&lock_exec_hash); + client_msg(thd->vio,MSG_OK,"Exec definition created"); + return 0; +err: + client_msg(thd->vio,MSG_CLIENT_ERR,error); + if (e) + manager_exec_free(e); + return 1; +} + +HANDLE_NOARG_DECL(show_exec) +{ + uint i; + client_msg_pre(thd->vio,MSG_INFO,"Exec_def\tPid\tExit_status\tCon_info\ +\tArguments"); + pthread_mutex_lock(&lock_exec_hash); + for (i=0;i<exec_hash.records;i++) + { + struct manager_exec* e=(struct manager_exec*)hash_element(&exec_hash,i); + manager_exec_print(thd->vio,e); + } + pthread_mutex_unlock(&lock_exec_hash); + client_msg(thd->vio,MSG_INFO,"End"); + return 0; +} + +static struct manager_exec* manager_exec_by_pid(pid_t pid) +{ + struct manager_exec* e; + uint i; + pthread_mutex_lock(&lock_exec_hash); + for (i=0;i<exec_hash.records;i++) + { + e=(struct manager_exec*)hash_element(&exec_hash,i); + if (e->pid==pid) + { + pthread_mutex_unlock(&lock_exec_hash); + return e; + } + } + pthread_mutex_unlock(&lock_exec_hash); + return 0; +} + +static void manager_exec_connect(struct manager_exec* e) +{ + int i; + for (i=0;i<manager_connect_retries;i++) + { + if (mysql_real_connect(&e->mysql,e->con_host,e->con_user,e->con_pass,0, + e->con_port,e->con_sock,0)) + return; + sleep(1); + } + e->error="Could not connect to MySQL server withing the number of tries"; +} + +static int manager_exec_launch(struct manager_exec* e) +{ + if (one_thread) + { + pid_t tmp_pid; + switch ((tmp_pid=fork())) + { + case -1: + e->error="Cannot fork"; + return 1; + case 0: + { + int err_code; + close(manager_sock); + err_code=execv(e->bin_path,e->args); + exit(err_code); + } + default: + e->pid=tmp_pid; + manager_exec_connect(e); + return 0; + } + } + else + { + if (write(to_launcher_pipe[1],&e->req_len,sizeof(int))!=sizeof(int) || + write(to_launcher_pipe[1],&e->num_args,sizeof(int))!=sizeof(int) || + write(to_launcher_pipe[1],e->data_buf,e->req_len)!=e->req_len) + { + e->error="Failed write request to launcher"; + return 1; + } + } + return 0; +} + +static char* arg_strmov(char* dest, const char* src, int n) +{ + char* dest_end = dest+n-1; + char c; + for (;dest<dest_end && (c=*src++);) + { + if (c=='%') + *dest++='%'; + *dest++=c; + } + return dest; +} + +static void manager_exec_print(Vio* vio,struct manager_exec* e) +{ + char buf[MAX_CLIENT_MSG_LEN]; + char* p=buf,*buf_end=buf+sizeof(buf)-1; + char** args=e->args; + + p=arg_strmov(p,e->ident,(int)(buf_end-p)-1); + *p++='\t'; + if (p>buf_end-15) + goto end; + p=int10_to_str(e->pid,p,10); + *p++='\t'; + p=int10_to_str(e->exit_code,p,10); + *p++='\t'; + + p=arg_strmov(p,e->con_user,(int)(buf_end-p)-1); + *p++='@'; + if (p==buf_end) + goto end; + p=arg_strmov(p,e->con_host,(int)(buf_end-p)-11); + *p++=':'; + if (p==buf_end-10) + goto end; + if (e->con_sock[0]) + { + p=arg_strmov(p,e->con_sock,(int)(buf_end-p)-1); + } + else + { + p=int10_to_str(e->con_port,p,10); + } + *p++='\t'; + + for(;p<buf_end && *args;args++) + { + p=arg_strmov(p,*args,(int)(buf_end-p)-1); + *p++='\t'; + } +end: + *p=0; + client_msg_pre(vio,MSG_INFO,buf); + return; +} + +static int authenticate(struct manager_thd* thd) +{ + char* buf_end; + client_msg(thd->vio,MSG_INFO, manager_greeting); + if (!(buf_end=read_line(thd))) + return -1; + client_msg(thd->vio,MSG_OK,"OK"); + return 0; +} + +static void print_time(FILE* fp) +{ + struct tm now; + time_t t; + time(&t); + localtime_r(&t,&now); + fprintf(fp,"[%d-%02d-%02d %02d:%02d:%02d] ", now.tm_year+1900, + now.tm_mon+1,now.tm_mday,now.tm_hour,now.tm_min, + now.tm_sec); +} + +static void die(const char* fmt, ...) +{ + va_list args; + va_start(args,fmt); + if (fmt) + { + if (errfp==stderr) + fprintf(errfp, "%s: ", my_progname); + else + { + print_time(errfp); + fprintf(errfp,"Fatal error: "); + } + vfprintf(errfp, fmt, args); + if (errno) + fprintf(errfp, " errno=%d", errno); + fprintf(errfp, "\n"); + fflush(errfp); + } + va_end(args); + clean_up(); + exit(1); +} + +void print_msg_type(int msg_type) +{ + const char* msg; + switch (msg_type) + { + case LOG_ERR: msg = "ERROR"; break; + case LOG_WARN: msg = "WARNING"; break; + case LOG_INFO: msg = "INFO"; break; +#ifndef DBUG_OFF + case LOG_DEBUG: msg = "DEBUG"; break; +#endif + default: msg = "UNKNOWN TYPE"; break; + } + fprintf(errfp," %s: ", msg); +} + +static void log_msg(const char* fmt, int msg_type, va_list args) +{ + pthread_mutex_lock(&lock_log); + print_time(errfp); + print_msg_type(msg_type); + vfprintf(errfp,fmt,args); + fputc('\n',errfp); + fflush(errfp); + pthread_mutex_unlock(&lock_log); +} + +#define LOG_MSG_FUNC(type,TYPE) inline static void log_ ## type \ + (const char* fmt,...) { \ + va_list args; \ + va_start(args,fmt); \ + log_msg(fmt,LOG_ ## TYPE,args);\ + } + +LOG_MSG_FUNC(err,ERR) +LOG_MSG_FUNC(warn,WARN) +LOG_MSG_FUNC(info,INFO) + +#ifndef DBUG_OFF +LOG_MSG_FUNC(debug,DEBUG) +#else +inline void log_debug(char* __attribute__((unused)) fmt,...) {} +#endif + +static pthread_handler_decl(process_launcher_messages, + __attribute__((unused)) arg) +{ + my_thread_init(); + for (;!in_shutdown;) + { + pid_t pid; + struct manager_exec* e; + char buf[MAX_LAUNCHER_MSG]; + if (read(from_launcher_pipe[0],buf,MAX_LAUNCHER_MSG)<0) + { + log_err("error reading launcher message"); + sleep(1); + continue; + } + switch (buf[0]) + { + case CHILD_START: + { + char* ident=buf+1; + int ident_len=strlen(ident); + memcpy(&pid,ident+ident_len+1,sizeof(pid)); + log_debug("process message - ident=%s,ident_len=%d,pid=%d",ident, + ident_len,pid); + pthread_mutex_lock(&lock_exec_hash); + log_debug("hash has %d records",exec_hash.records); + e=(struct manager_exec*)hash_search(&exec_hash,ident,ident_len); + if (e) + { + pthread_mutex_lock(&e->lock); + e->pid=pid; + pthread_cond_broadcast(&e->cond); + pthread_mutex_unlock(&e->lock); + } + pthread_mutex_unlock(&lock_exec_hash); + log_debug("unlocked mutex"); + break; + } + case CHILD_STOP: + memcpy(&pid,buf+1,sizeof(pid)); + e=manager_exec_by_pid(pid); + if (e) + { + pthread_mutex_lock(&e->lock); + e->pid=0; + memcpy(&e->exit_code,buf+1+sizeof(pid),sizeof(int)); + pthread_cond_broadcast(&e->cond); + pthread_mutex_unlock(&e->lock); + } + break; + default: + log_err("Got invalid launcher message"); + break; + } + } + return 0; +} + +static pthread_handler_decl(process_connection,arg) +{ + struct manager_thd* thd = (struct manager_thd*)arg; + my_thread_init(); + pthread_detach_this_thread(); + for (;!thd->finished;) + { + char* buf_end; + if ((!(buf_end=read_line(thd)) || exec_line(thd,thd->cmd_buf,buf_end)) + && thd->fatal) + { + log_err("Thread aborted"); + break; + } + } + manager_thd_free(thd); + pthread_exit(0); +} + +static void client_msg_raw(Vio* vio, int err_code, int pre, const char* fmt, + va_list args) +{ + char buf[MAX_CLIENT_MSG_LEN],*p,*buf_end; + p=buf; + buf_end=buf+sizeof(buf); + p=int10_to_str(err_code,p,10); + if (pre) + *p++='-'; + *p++=' '; + p+=my_vsnprintf(p,buf_end-p,fmt,args); + if (p>buf_end-2) + p=buf_end - 2; + *p++='\r'; + *p++='\n'; + if (vio_write(vio,buf,(uint)(p-buf))<=0) + log_err("Failed writing to client: errno=%d"); +} + +static void client_msg(Vio* vio, int err_code, const char* fmt, ...) +{ + va_list args; + va_start(args,fmt); + client_msg_raw(vio,err_code,0,fmt,args); +} + +static void client_msg_pre(Vio* vio, int err_code, const char* fmt, ...) +{ + va_list args; + va_start(args,fmt); + client_msg_raw(vio,err_code,1,fmt,args); +} + +static char* read_line(struct manager_thd* thd) +{ + char* p=thd->cmd_buf; + char* buf_end = thd->cmd_buf + manager_max_cmd_len; + int escaped = 0; + for (;p<buf_end;) + { + int len,read_len; + char *block_end,*p_back; + read_len = min(NET_BLOCK,(uint)(buf_end-p)); + if ((len=vio_read(thd->vio,p,read_len))<=0) + { + log_err("Error reading command from client"); + return 0; + } + block_end=p+len; + /* a trick to unescape in place */ + for (p_back=p;p<block_end;p++) + { + char c=*p; + if (c==ESCAPE_CHAR) + { + if (!escaped) + { + escaped=1; + continue; + } + else + escaped=0; + } + if (c==EOL_CHAR && !escaped) + break; + *p_back++=c; + escaped=0; + } + if (p!=block_end) + { + *p_back=0; + return p_back; + } + } + client_msg(thd->vio,MSG_CLIENT_ERR,"Command line too long"); + return 0; +} + +static void handle_child(int __attribute__((unused)) sig) +{ + pid_t child; + int child_status; + + for(;(child=waitpid(-1,&child_status,WNOHANG))>0;) + { + char msg_buf[1+sizeof(int)+sizeof(int)]; + msg_buf[0]=CHILD_STOP; + memcpy(msg_buf+1,&child,sizeof(int)); + memcpy(msg_buf+1+sizeof(int),&child_status,sizeof(int)); + if (write(from_launcher_pipe[1],msg_buf,sizeof(msg_buf))!=sizeof(msg_buf)) + log_err("launcher: error writing message on child exit"); + } + signal(SIGCHLD,handle_child); +} + +struct manager_thd* manager_thd_new(Vio* vio) +{ + struct manager_thd* tmp; + if (!(tmp=(struct manager_thd*)my_malloc(sizeof(*tmp)+manager_max_cmd_len, + MYF(0)))) + { + log_err("Out of memory in manager_thd_new"); + return 0; + } + tmp->vio=vio; + tmp->user[0]=0; + tmp->priv_flags=0; + tmp->fatal=tmp->finished=0; + tmp->cmd_buf=(char*)tmp+sizeof(*tmp); + return tmp; +} + +static void manager_thd_free(struct manager_thd* thd) +{ + if (thd->vio) + vio_close(thd->vio); + my_free((byte*)thd->vio,MYF(0)); +} + +static void clean_up() +{ + pthread_mutex_lock(&lock_shutdown); + if (in_shutdown) + { + pthread_mutex_unlock(&lock_shutdown); + return; + } + in_shutdown = 1; + pthread_mutex_unlock(&lock_shutdown); + log_info("Shutdown started"); + if (manager_sock) + close(manager_sock); + log_info("Ended"); + if (errfp != stderr) + fclose(errfp); + hash_free(&exec_hash); +} + +static void print_version(void) +{ + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MANAGER_VERSION, + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} + +static void usage() +{ + print_version(); + printf("MySQL AB, by Sasha\n"); + printf("This software comes with ABSOLUTELY NO WARRANTY\n\n"); + printf("Manages instances of MySQL server.\n\n"); + printf("Usage: %s [OPTIONS]", my_progname); + printf("\n\ + -?, --help Display this help and exit.\n"); +#ifndef DBUG_OFF + puts("\ + -#, --debug=[...] Output debug log. Often this is 'd:t:o,filename`"); +#endif + printf("\ + -P, --port=... Port number to listen on.\n\ + -l, --log=... Path to log file.\n\ + -b, --bind-address=... Address to listen on.\n\ + -B, --tcp-backlog==... Size of TCP/IP listen queue.\n\ + -g, --greeting= Set greeting on connect \n\ + -m, --max-command-len Maximum command length \n\ + -d, --one-thread Use one thread ( for debugging) \n\ + -C, --connect-retries Number of attempts to establish MySQL connection \n\ + -m, --max-command-len Maximum command length \n\ + -V, --version Output version information and exit.\n\n"); +} + +static int parse_args(int argc, char **argv) +{ + int c, option_index = 0; + while ((c=getopt_long(argc,argv,"P:?#:Vl:b:B:g:m:dC:p:", + long_options,&option_index)) != EOF) + { + switch (c) + { + case '#': + DBUG_PUSH(optarg ? optarg : "d:t:O,/tmp/mysqlmgrd.trace"); + break; + case 'd': + one_thread=1; + break; + case 'p': + manager_pw_file=MANAGER_PW_FILE; + break; + case 'C': + manager_connect_retries=atoi(optarg); + break; + case 'P': + manager_port=atoi(optarg); + break; + case 'm': + manager_max_cmd_len=atoi(optarg); + break; + case 'g': + manager_greeting=optarg; + case 'b': + manager_bind_addr = inet_addr(optarg); + break; + case 'B': + manager_back_log = atoi(optarg); + break; + case 'l': + manager_log_file=optarg; + break; + case 'V': + print_version(); + exit(0); + case '?': + usage(); + exit(0); + default: + usage(); + exit(1); + } + } + return 0; +} + +static int init_server() +{ + int arg=1; + log_info("Started"); + if ((manager_sock=socket(PF_INET,SOCK_STREAM,0)) < 0) + die("Could not create socket"); + bzero((char*)&manager_addr, sizeof(manager_addr)); + manager_addr.sin_family = AF_INET; + manager_addr.sin_addr.s_addr = manager_bind_addr; + manager_addr.sin_port = htons(manager_port); + setsockopt(manager_sock,SOL_SOCKET, SO_REUSEADDR,(char*)&arg,sizeof(arg)); + if (bind(manager_sock,(struct sockaddr*)&manager_addr, sizeof(manager_addr)) < 0) + die("Could not bind"); + if (listen(manager_sock,manager_back_log) < 0) + die("Could not listen"); + + return 0; +} + +static int run_server_loop() +{ + pthread_t th; + struct manager_thd *thd; + int client_sock,len; + Vio* vio; + + for (;!shutdown_requested;) + { + len=sizeof(struct sockaddr_in); + if ((client_sock=accept(manager_sock,(struct sockaddr*)&manager_addr,&len))<0) + { + if (shutdown_requested) + break; + if (errno != EAGAIN) + { + log_warn("Error in accept, errno=%d", errno); + sleep(1); /* avoid tying up CPU if accept is broken */ + } + continue; + } + if (shutdown_requested) + break; + if (!(vio=vio_new(client_sock,VIO_TYPE_TCPIP,FALSE))) + { + log_err("Could not create I/O object"); + close(client_sock); + continue; + } + if (!(thd=manager_thd_new(vio))) + { + log_err("Could not create thread object"); + vio_close(vio); + continue; + } + + if (authenticate(thd)) + { + client_msg(vio,MSG_ACCESS, "Access denied"); + manager_thd_free(thd); + continue; + } + if (shutdown_requested) + break; + if (one_thread) + { + process_connection((void*)thd); + manager_thd_free(thd); + continue; + } + else if (pthread_create(&th,0,process_connection,(void*)thd)) + { + client_msg(vio,MSG_INTERNAL_ERR,"Could not create thread, errno=%d", + errno); + manager_thd_free(thd); + continue; + } + } + return 0; +} + +static FILE* open_log_stream() +{ + FILE* fp; + if (!(fp=fopen(manager_log_file,"a"))) + die("Could not open log file '%s'", manager_log_file); + return fp; +} + +static byte* get_user_key(const byte* u, uint* len, + my_bool __attribute__((unused)) t) +{ + register const char* key; + key = ((struct manager_user*)u)->user; + *len = ((struct manager_user*)u)->user_len; + return (byte*)key; +} + +static byte* get_exec_key(const byte* e, uint* len, + my_bool __attribute__((unused)) t) +{ + register const char* key; + key = ((struct manager_exec*)e)->ident; + *len = ((struct manager_exec*)e)->ident_len; + return (byte*)key; +} + +static void init_arg_array(char* arg_str,char** args,uint arg_count) +{ + char* p = arg_str; + for (;arg_count>0;arg_count--) + { + *args++=p; + p += strlen(p)+1; + } + *args=0; +} + +static uint tokenize_args(char* arg_start,char** arg_end) +{ + char* p, *p_write,*p_end; + uint arg_count=0; + int quoted=0,escaped=0,last_space=0; + p_end=*arg_end; + p_write=p=arg_start; + for(;p<p_end;p++) + { + char c = *p; + switch (c) + { + case ' ': + case '\r': + case '\n': + if (!quoted) + { + if (!last_space) + { + *p_write++=0; + arg_count++; + last_space=1; + } + } + else + *p_write++=c; + escaped=0; + break; + case '"': + if (!escaped) + quoted=!quoted; + else + *p_write++=c; + last_space=0; + escaped=0; + break; + case '\\': + if (!escaped) + escaped=1; + else + { + *p_write++=c; + escaped=0; + } + last_space=0; + break; + default: + escaped=last_space=0; + *p_write++=c; + break; + } + } + if (!last_space && p_write>arg_start) + arg_count++; + *p_write=0; + *arg_end=p_write; + log_debug("arg_count=%d,arg_start='%s'",arg_count,arg_start); + return arg_count; +} + + +static struct manager_exec* manager_exec_new(char* arg_start,char* arg_end) +{ + struct manager_exec* tmp; + char* first_arg; + uint arg_len,num_args; + num_args=tokenize_args(arg_start,&arg_end); + arg_len=(uint)(arg_end-arg_start)+1; /* include \0 terminator*/ + if (!(tmp=(struct manager_exec*)my_malloc(sizeof(*tmp)+arg_len+ + sizeof(char*)*num_args,MYF(0)))) + return 0; + if (num_args<2) + { + tmp->error="Too few arguments"; + return tmp; + } + tmp->data_buf=(char*)tmp+sizeof(*tmp); + memcpy(tmp->data_buf,arg_start,arg_len); + tmp->req_len=arg_len; + tmp->args=(char**)(tmp->data_buf+arg_len); + tmp->num_args=num_args; + tmp->ident=tmp->data_buf; + tmp->ident_len=strlen(tmp->ident); + first_arg=tmp->ident+tmp->ident_len+1; + init_arg_array(first_arg,tmp->args,num_args-1); + strmov(tmp->con_user,"root"); + tmp->con_pass[0]=0; + tmp->con_sock[0]=0; + tmp->con_port=MYSQL_PORT; + memcpy(tmp->con_host,"localhost",10); + tmp->bin_path=tmp->args[0]; + tmp->pid=0; + tmp->exit_code=0; + tmp->th=0; + pthread_mutex_init(&tmp->lock,0); + pthread_cond_init(&tmp->cond,0); + mysql_init(&tmp->mysql); + tmp->error=0; + return tmp; +} + +static void manager_exec_free(void* e) +{ + mysql_close(&((struct manager_exec*)e)->mysql); + my_free(e,MYF(0)); +} + +static struct manager_user* manager_user_new(char* buf) +{ + struct manager_user* tmp; + char* p,*user_end; + char c; + if (!(tmp=(struct manager_user*)my_malloc(sizeof(*tmp),MYF(0)))) + return 0; + p=tmp->user; + user_end=p+MAX_USER_NAME-1; + for (;(c=*buf) && p<user_end;buf++) + { + if (c == ':') + { + *p=0; + tmp->user_len=p-tmp->user; + buf++; + break; + } + else + *p++=c; + } + if (!c) + tmp->error="Missing ':'"; + if (p == user_end) + tmp->error="Username too long"; + if (tmp->error) + return tmp; + if (strlen(buf) < MD5_LEN) + { + tmp->error="Invalid MD5 sum, too short"; + return tmp; + } + memcpy(tmp->md5_pass,buf,MD5_LEN); + tmp->error=0; + return tmp; +} + +static void manager_user_free(void* u) +{ + my_free((gptr)u,MYF(0)); +} + +static void init_user_hash() +{ + FILE* f; + char buf[80]; + int line_num=1; + if (hash_init(&user_hash,1024,0,0,get_user_key,manager_user_free,MYF(0))) + die("Could not initialize user hash"); + if (!(f=fopen(manager_pw_file,"r"))) + die("Could not open password file '%s'", manager_pw_file); + for (;;line_num++) + { + struct manager_user* u; + if (!fgets(buf,sizeof(buf),f) || feof(f)) + break; + if (buf[0] == '#') + continue; + if (!(u=manager_user_new(buf))) + die("Out of memory while reading user line"); + if (u->error) + { + die("Error on line %d of '%s': %s",line_num,manager_pw_file, u->error); + } + else + { + hash_insert(&user_hash,(gptr)u); + } + } + fclose(f); +} + +static void init_globals() +{ + if (hash_init(&exec_hash,1024,0,0,get_exec_key,manager_exec_free,MYF(0))) + die("Exec hash initialization failed"); + if (!one_thread) + { + fork_launcher(); + if (pthread_create(&launch_msg_th,0,process_launcher_messages,0)) + die("Could not start launcher message handler thread"); + } + init_user_hash(); + loop_th=pthread_self(); + signal(SIGPIPE,handle_sigpipe); +} + +static void run_launcher_loop() +{ + for (;;) + { + int req_len,ident_len,num_args; + char* request_buf=0; + pid_t pid; + char* exec_path,*ident; + char** args=0; + + if (read(to_launcher_pipe[0],&req_len,sizeof(int))!=sizeof(int) || + read(to_launcher_pipe[0],&num_args,sizeof(int))!=sizeof(int) || + !(request_buf=(char*)my_malloc(req_len+sizeof(pid)+2,MYF(0))) || + !(args=(char**)my_malloc(num_args*sizeof(char*),MYF(0))) || + read(to_launcher_pipe[0],request_buf+1,req_len)!=req_len) + { + log_err("launcher: Error reading request"); + my_free((gptr)request_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free((gptr)args,MYF(MY_ALLOW_ZERO_PTR)); + sleep(1); + continue; + } + ident=request_buf+1; + ident_len=strlen(ident); + exec_path=ident+ident_len+1; + log_debug("num_args=%d,req_len=%d,ident=%s,ident_len=%d,exec_path=%s", + num_args, + req_len,ident,ident_len,exec_path); + init_arg_array(exec_path,args,num_args-1); + + switch ((pid=fork())) + { + case -1: + log_err("launcher: cannot fork"); + sleep(1); + break; + case 0: + if (execv(exec_path,args)) + log_err("launcher: cannot exec %s",exec_path); + exit(1); + default: + request_buf[0]=CHILD_START; + memcpy(request_buf+ident_len+2,&pid,sizeof(pid)); + if (write(from_launcher_pipe[1],request_buf,ident_len+2+sizeof(pid))<0) + log_err("launcher: error sending launch status report"); + break; + } + my_free((gptr)request_buf,MYF(0)); + my_free((gptr)args,MYF(0)); + } +} + +static void fork_launcher() +{ + if (pipe(to_launcher_pipe) || pipe(from_launcher_pipe)) + die("Could not create launcher pipes"); + switch ((launcher_pid=fork())) + { + case 0: + signal(SIGCHLD,handle_child); + run_launcher_loop(); + exit(0); + case -1: die("Could not fork the launcher"); + default: return; + } +} + +static int daemonize() +{ + switch (fork()) + { + case -1: + die("Cannot fork"); + case 0: + errfp = open_log_stream(); + init_globals(); + close(0); + close(1); + close(2); + init_server(); + run_server_loop(); + clean_up(); + break; + default: + break; + } + return 0; +} + +int main(int argc, char** argv) +{ + char c; + stack_bottom=&c; + MY_INIT(argv[0]); + errfp = stderr; + parse_args(argc,argv); + pthread_mutex_init(&lock_log,0); + pthread_mutex_init(&lock_shutdown,0); + pthread_mutex_init(&lock_exec_hash,0); + pthread_mutex_init(&lock_launch_thd,0); + pthread_cond_init(&cond_launch_thd,0); +#ifdef DO_STACKTRACE + signal(SIGSEGV,handle_segfault); +#endif + if (one_thread) + { + init_globals(); + init_server(); + run_server_loop(); + clean_up(); + return 0; + } + else + return daemonize(); +} + + + + + + + + + diff --git a/vio/Makefile.am b/vio/Makefile.am index 9bb8691eee6..7119c278862 100644 --- a/vio/Makefile.am +++ b/vio/Makefile.am @@ -14,20 +14,21 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -INCLUDES = -I$(srcdir)/../include -I../include \ - @OPENSSL_INCLUDES@ -LDADD = libvio.la -pkglib_LTLIBRARIES = libvio.la -noinst_PROGRAMS = +INCLUDES = -I$(srcdir)/../include -I../include $(openssl_includes) +LDADD = libvio.a $(openssl_libs) +pkglib_LIBRARIES = libvio.a +noinst_PROGRAMS = test-ssl test-sslserver test-sslclient noinst_HEADERS = -libvio_la_SOURCES = \ - Vio.cc VioAcceptorFd.cc \ - VioConnectorFd.cc VioFd.cc \ - VioHandle.cc VioSSL.cc \ - VioSSLFactoriesFd.cc VioSocket.cc \ - auto.cc hostnamexx.cc \ - vdbug.cc version.cc \ - vmem.cc violitexx.cc +test_ssl_SOURCES = test-ssl.c +test_ssl_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ + ../strings/libmystrings.a libvio.a $(openssl_libs) +test_sslserver_SOURCES = test-sslserver.c +test_sslserver_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ + ../strings/libmystrings.a libvio.a $(openssl_libs) +test_sslclient_SOURCES = test-sslclient.c +test_sslclient_LDADD = ../dbug/libdbug.a libvio.a ../mysys/libmysys.a \ + ../strings/libmystrings.a libvio.a $(openssl_libs) +libvio_a_SOURCES = vio.c viosocket.c viossl.c viosslfactories.c OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\ __math.h time.h __time.h unistd.h __unistd.h types.h \ diff --git a/vio/Vio.cc b/vio/Vio.cc deleted file mode 100644 index b15f9cfa6d2..00000000000 --- a/vio/Vio.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif -#include "vio-global.h" - -VIO_NS_BEGIN - -void -Vio::release() -{ - delete this; -} - -Vio::~Vio() -{ -} - -VIO_NS_END diff --git a/vio/Vio.h b/vio/Vio.h deleted file mode 100644 index 959d472873f..00000000000 --- a/vio/Vio.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Abstract Virtual IO interface - class Vio. Heavily - * influenced by Berkeley sockets and oriented toward MySQL. - */ - -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -** Modified by Monty -*/ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, - VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL}; - -class Vio { -public: - virtual bool is_open() const = 0; - virtual int read(vio_ptr buf, int size) = 0; - virtual int write(const vio_ptr buf, int size) = 0; - virtual int blocking(bool onoff) = 0; - virtual bool blocking() const = 0; - virtual bool fcntl() const = 0; - virtual int fastsend(bool onoff = true) = 0; - virtual int keepalive(bool onoff) = 0; - virtual bool should_retry() const = 0; - virtual int close() = 0; - virtual void release(); - virtual const char* description() const = 0; - virtual bool peer_addr(char *buf) const = 0; - virtual const char* cipher_description() const = 0; - virtual int vio_errno(); - virtual ~Vio(); -}; - -/* Macros to simulate the violite C interface */ - - -Vio *vio_new(my_socket sd, enum enum_vio_type type, - my_bool localhost); -#ifdef __WIN__ -Vio* vio_new_win32pipe(HANDLE hPipe); -#endif - -#define vio_delete(vio) delete vio -#define vio_read(vio,buf,size) vio->read(buf,size) -#define vio_write(vio,buf,size) vio->write(buf,size) -#define vio_blocking(vio,mode) vio->blocking(mode) -#define vio_is_blocking(vio) vio->is_blocking() -#define vio_fastsend(vio,mode) vio->fastsend(mode) -#define vio_keepalive(vio,mode) vio->keepalive(mode) -#define vio_shouldretry(vio) vio->shouldretry(mode) -#define vio_close(vio) vio->close() -#define vio_description(vio) vio->description() -#define vio_errno(Vio *vio) vio->errno() -#define vio_peer_addr(vio,buf) vio->peer_addr(buf) -#define vio_in_addr(vio,in) vio->in_addr(in) - -VIO_NS_END diff --git a/vio/VioAcceptorFd.cc b/vio/VioAcceptorFd.cc deleted file mode 100644 index 4572e2cb71b..00000000000 --- a/vio/VioAcceptorFd.cc +++ /dev/null @@ -1,18 +0,0 @@ - -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -#include "vio-global.h" -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif - -VIO_NS_BEGIN - -VioAcceptorFd::~VioAcceptorFd() -{ -} - -VIO_NS_END diff --git a/vio/VioAcceptorFd.h b/vio/VioAcceptorFd.h deleted file mode 100644 index e0441780db9..00000000000 --- a/vio/VioAcceptorFd.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -/* - * Abstract acceptor. - */ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioAcceptorFd -{ -public: - virtual ~VioAcceptorFd(); - virtual Vio* accept( int fd) = 0; -}; - -VIO_NS_END diff --git a/vio/VioConnectorFd.cc b/vio/VioConnectorFd.cc deleted file mode 100644 index 49f81077a84..00000000000 --- a/vio/VioConnectorFd.cc +++ /dev/null @@ -1,22 +0,0 @@ - -/* - * Unneccessary virtual destructor. - */ - -#include "vio-global.h" -#include <unistd.h> -#include <fcntl.h> -#include <assert.h> - -#include "viotypes.h" -#include "Vio.h" -#include "VioConnectorFd.h" - -VIO_NS_BEGIN - -VioConnectorFd::~VioConnectorFd() -{ -} - -VIO_NS_END - diff --git a/vio/VioConnectorFd.h b/vio/VioConnectorFd.h deleted file mode 100644 index da684df5f1b..00000000000 --- a/vio/VioConnectorFd.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Abstract connector. The file (or socket) descriptor has to be - * prepared. - */ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioConnectorFd -{ -public: - virtual ~VioConnectorFd(); - virtual Vio* connect(int fd) = 0; -}; - -VIO_NS_END diff --git a/vio/VioFd.cc b/vio/VioFd.cc deleted file mode 100644 index da59798fc25..00000000000 --- a/vio/VioFd.cc +++ /dev/null @@ -1,156 +0,0 @@ -/* -** Virtual I/O library for files -** Written by Andrei Errapart <andreie@no.spam.ee> -** Checked and modfied by Monty -*/ - -#include "vio-global.h" -#include <assert.h> - -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif - -VIO_NS_BEGIN - -VioFd::VioFd( int fd) : fd_(fd) -{ - sprintf(desc_, "VioFd(%d)", fd_); -} - -VioFd:: ~VioFd() -{ - if (fd_ >= 0) - { - it r = ::close(fd_); - if ( r < 0) - { - /* FIXME: error handling (Not Critical for MySQL) */ - } - } -} - - -bool -VioFd::open() const -{ - return fd_ >= 0; -} - -int -VioFd::read(vio_ptr buf, int size) -{ - assert(fd_>=0); - return ::read(fd_, buf, size); -} - -int -VioFd::write(const vio_ptr buf, int size) -{ - assert(fd_>=0); - return ::write(fd_, buf, size); -} - -int -VioFd::blocking(bool onoff) -{ - if (onoff) - return 0; - else - return -1; -} - -bool -VioFd::blocking() const -{ - return true; -} - -int -VioFd::fastsend(bool tmp) -{ - return 0; -} - - -int -VioFd::keepalive(boolonoff) -{ - return -2; // Why -2 ? (monty) -} - -bool -VioFd::fcntl() const -{ - return FALSE; -} - -bool -VioFd::should_retry() const -{ - return FALSE; -} - -int -VioFd::fcntl(int cmd) -{ - assert(fd_>=0); - return ::fcntl(fd_, cmd); -} - -int -VioFd::fcntl(int cmd, long arg) -{ - assert(fd_>=0); - return ::fcntl(fd_, cmd, arg); -} - -int -VioFd::fcntl(int cmd, struct flock* lock) -{ - assert(fd_>=0); - return ::fcntl(fd_, cmd, lock); -} - -int -VioFd::close() -{ - int r = -2; - if (fd_>=0) - { - - if ((r= ::close(fd_)) == 0) - fd_ = -1; - } - else - { - /* FIXME: error handling */ - } - return r; -} - -const char* -VioFd::description() const -{ - return desc_; -} - -const char* -VioFd::peer_addr() const -{ - return ""; -} - -const char* -VioFd::peer_name() const -{ - return "localhost"; -} - -const char* -VioFd::cipher_description() const -{ - return ""; -} - -VIO_NS_END diff --git a/vio/VioFd.h b/vio/VioFd.h deleted file mode 100644 index f1c009d848c..00000000000 --- a/vio/VioFd.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Concrete Vio around a file descriptor. - */ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioFd : public Vio -{ -public: - VioFd( int fd); - virtual ~VioFd(); - virtual bool open() const; - virtual int read( vio_ptr buf, int size); - virtual int write( const vio_ptr buf, int size); - virtual bool blocking() const; - virtual int blocking(bool onoff); - virtual int fastsend(bool onoff=true); - virtual int keepalive( bool onoff); - virtual bool fcntl() const; - virtual bool should_retry() const; - virtual int fcntl( int cmd); - virtual int fcntl( int cmd, long arg); - virtual int fcntl( int cmd, struct flock* lock); - virtual int close(); - virtual const char* description() const; - virtual const char* peer_addr() const; - virtual bool peer_name(char *buf) const; - virtual const char* cipher_description() const; -private: - int fd_; - char desc_[100]; -}; - -VIO_NS_END diff --git a/vio/VioPipe.cc b/vio/VioPipe.cc deleted file mode 100644 index 5d6f9f36496..00000000000 --- a/vio/VioPipe.cc +++ /dev/null @@ -1,25 +0,0 @@ -/* -** Virtual I/O library for Windows named pipes -** Written by Monty -*/ - - -#ifdef __WIN32__ -#include "vio-global.h" - -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif - -VIO_NS_BEGIN - - - - - - - - -VIO_NS_END - -#endif /* WIN32 */ diff --git a/vio/VioPipe.h b/vio/VioPipe.h deleted file mode 100644 index a6bb587c548..00000000000 --- a/vio/VioPipe.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Concrete Vio around Handle. - */ - -#ifdef __WIN__ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioPipe : public Vio -{ -public: - VioPipe(int fd); - virtual ~VioPipe(); - virtual bool is_open() const; - virtual int read(vio_ptr buf, int size); - virtual int write(const vio_ptr buf, int size); - virtual int blocking(bool onoff); - virtual bool blocking() const; - virtual bool fcntl() const; - virtual int fastsend(bool onoff = true); - virtual int keepalive(bool onoff); - virtual bool should_retry() const; - virtual int close(); - virtual void release(); - virtual const char* description() const; - virtual bool peer_addr(char *buf) const; - virtual const char* cipher_description() const { return "";} - virtual int vio_errno(); -private: -}; - -VIO_NS_END - -#endif /* WIN32 */ diff --git a/vio/VioSSL.cc b/vio/VioSSL.cc deleted file mode 100644 index 15964c09aba..00000000000 --- a/vio/VioSSL.cc +++ /dev/null @@ -1,292 +0,0 @@ -/* -** Virtual I/O library for SSL wrapper -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -/* - * This file has some huge DBUG_ statements. Boy, this is silly... - */ - -#include "vio-global.h" -#ifdef VIO_HAVE_OPENSSL -#include <assert.h> -#include <netinet/in.h> -#include <openssl/x509.h> -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/pem.h> - -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif - -VIO_NS_BEGIN - -#define this_ssl_con my_static_cast(SSL*)(this->ssl_con_) -#define this_bio my_static_cast(BIO*)(this->bio_) -typedef char* dataptr_t; - -static void -report_errors() -{ - unsigned long l; - const char* file; - const char* data; - int line,flags; - DBUG_ENTER("VioSSLConnectorFd::report_errors"); - - while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) - { - char buf[200]; - DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), - file,line,(flags&ERR_TXT_STRING)?data:"")) ; - } - DBUG_VOID_RETURN; -} - -//FIXME: duplicate code! -VioSSL::VioSSL(int fd, - vio_ptr ssl_context, - int state) - : bio_(0), ssl_con_(0), open_(FALSE), sd_(new VioSocket(fd)) -{ - DBUG_ENTER("VioSSL::VioSSL"); - DBUG_PRINT("enter", ("this=%p, fd=%d, ssl_context=%p, state=%d", - this, fd, ssl_context, state)); - assert(fd!=0); - assert(ssl_context!=0); - assert(state==state_connect || state==state_accept); - - if (!init_bio_(fd, ssl_context, state, BIO_NOCLOSE)) - open_ = true; - DBUG_VOID_RETURN; -} - - -VioSSL::VioSSL(VioSocket* sd, - vio_ptr ssl_context, - int state) - :bio_(0), ssl_con_(0), open_(FALSE), sd_(sd) -{ - DBUG_ENTER("VioSSL::VioSSL"); - DBUG_PRINT("enter", - ("this=%p, sd=%s, ssl_context=%p, state=%d", - this, sd ? sd->description() : "0", ssl_context, state)); - assert(sd != 0); - assert(ssl_context != 0); - assert(state == state_connect || state==state_accept); - - if (!init_bio_(sd->sd_, ssl_context, state, BIO_NOCLOSE)) - open_ = true; - DBUG_VOID_RETURN; -} - -VioSSL::~VioSSL() -{ - DBUG_ENTER("VioSSL::~VioSSL"); - DBUG_PRINT("enter", ("this=%p", this)); - if (ssl_con_!=0) - { - SSL_shutdown(this_ssl_con); - SSL_free(this_ssl_con); - } - if (sd_!=0) - delete sd_; - /* FIXME: no need to close bio? */ - /* - if (bio_!=0) - BIO_free(this_bio); - */ - DBUG_VOID_RETURN; -} - -bool -VioSSL::is_open() const -{ - return open_; -} - -int -VioSSL::read(vio_ptr buf, int size) -{ - int r; - DBUG_ENTER("VioSSL::read"); - DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); - assert(this_ssl_con != 0); - r = SSL_read(this_ssl_con, my_static_cast(dataptr_t)(buf), size); - if ( r< 0) - report_errors(); - DBUG_PRINT("exit", ("r=%d", r)); - DBUG_RETURN(r); -} - -int -VioSSL::write(const vio_ptr buf, int size) -{ - int r; - DBUG_ENTER("VioSSL::write"); - DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); - assert(this_ssl_con!=0); - r = SSL_write(this_ssl_con, my_static_cast(dataptr_t)(buf), size); - if (r<0) - report_errors(); - DBUG_PRINT("exit", ("r=%d", r)); - DBUG_RETURN(r); -} - -int -VioSSL::blocking(bool onoff) -{ - int r; - DBUG_ENTER("VioSSL::blocking"); - DBUG_PRINT("enter", ("this=%p, onoff=%s", this, onoff?"true":"false")); - r = sd_->blocking(onoff); - DBUG_PRINT("exit", ("r=%d", (int)r )); - DBUG_RETURN(r); -} - -bool -VioSSL::blocking() const -{ - bool r; - DBUG_ENTER("VioSSL::blocking"); - DBUG_PRINT("enter", ("this=%p", this)); - r = sd_->blocking(); - DBUG_PRINT("exit", ("r=%d", (int)r )); - DBUG_RETURN(r); -} - -int -VioSSL::fastsend(bool onoff) -{ - int r; - DBUG_ENTER("VioSSL::fastsend"); - DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); - r = sd_->fastsend(onoff); - DBUG_PRINT("exit", ("r=%d", (int)r )); - DBUG_RETURN(r); -} - -int VioSSL::keepalive(bool onoff) -{ - int r; - DBUG_ENTER("VioSSL::keepalive"); - DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); - r = sd_->keepalive(onoff); - DBUG_PRINT("exit", ("r=%d", int(r) )); - DBUG_RETURN(r); -} - -bool -VioSSL::fcntl() const -{ - bool r; - DBUG_ENTER("VioSSL::fcntl"); - DBUG_PRINT("enter", ("this=%p", this)); - r = sd_->fcntl(); - DBUG_PRINT("exit", ("r=%d", (int)r )); - DBUG_RETURN(r); -} - -bool -VioSSL::should_retry() const -{ - bool r; - DBUG_ENTER("VioSSL::should_retry"); - DBUG_PRINT("enter", ("this=%p", this)); - r = sd_->should_retry(); - DBUG_PRINT("exit", ("r=%d", (int)r )); - DBUG_RETURN(r); -} - -int -VioSSL::close() -{ - int r= -2; - DBUG_ENTER("VioSSL::close"); - DBUG_PRINT("enter", ("this=%p", this)); - if (ssl_con) - { - r = SSL_shutdown(this_ssl_con); - SSL_free(this_ssl_con); - ssl_con_ = 0; - BIO_free(this_bio); - bio_ = 0; - } - DBUG_PRINT("exit", ("r=%d", r)); - DBUG_RETURN(r); -} - -const char* -VioSSL::description() const -{ - return desc_; -} - -const char* -VioSSL::peer_addr() const -{ - if (sd_!=0) - return sd != 0 ? sd_->peer_addr() : ""; -} - -const char* -VioSSL::peer_name() const -{ - return sd != 0 ? sd_->peer_name() : ""; -} - -const char* -VioSSL::cipher_description() const -{ - return SSL_get_cipher_name(this_ssl_con); -} - - -int -VioSSL::init_bio_(int fd, - vio_ptr ssl_context, - int state, - int bio_flags) -{ - DBUG_ENTER("VioSSL::init_bio_"); - DBUG_PRINT("enter", - ("this=%p, fd=%p, ssl_context=%p, state=%d, bio_flags=%d", - this, fd, ssl_context, state, bio_flags)); - - - if (!(ssl_con_ = SSL_new(my_static_cast(SSL_CTX*)(ssl_context)))) - { - DBUG_PRINT("error", ("SSL_new failure")); - report_errors(); - DBUG_RETURN(-1); - } - if (!(bio_ = BIO_new_socket(fd, bio_flags))) - { - DBUG_PRINT("error", ("BIO_new_socket failure")); - report_errors(); - SSL_free(ssl_con_); - ssl_con_ =0; - DBUG_RETURN(-1); - } - SSL_set_bio(this_ssl_con, this_bio, this_bio); - switch(state) { - case state_connect: - SSL_set_connect_state(this_ssl_con); - break; - case state_accept: - SSL_set_accept_state(this_ssl_con); - break; - default: - assert(0); - } - sprintf(desc_, "VioSSL(%d)", fd); - ssl_cip_ = new SSL_CIPHER ; - DBUG_RETURN(0); -} - - -VIO_NS_END - -#endif /* VIO_HAVE_OPENSSL */ - diff --git a/vio/VioSSL.h b/vio/VioSSL.h deleted file mode 100644 index 6446c10700e..00000000000 --- a/vio/VioSSL.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Concrete Vio around OpenSSL's SSL structure. - */ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioSocket; - -class VioSSL : public Vio -{ -public: - enum { - state_connect = 1, - state_accept = 2 - }; -public: - VioSSL(int fd, vio_ptr ssl_context, int state); - VioSSL(VioSocket* sd, vio_ptr ssl_context, int state); - virtual ~VioSSL(); - virtual bool open() const; - virtual int read( vio_ptr buf, int size); - virtual int write( const vio_ptr buf, int size); - virtual bool blocking() const; - virtual int blocking(bool onoff); - virtual int fastsend(bool onoff=true); - virtual int keepalive(bool onoff); - virtual bool fcntl() const; - virtual bool should_retry() const; - virtual int close(); - virtual const char* description() const; - virtual const char* peer_addr() const; - virtual const char* peer_name() const; - virtual const char* cipher_description() const; - -private: - int init_bio_(int fd, - vio_ptr ssl_context, - int state, - int bio_flags); - vio_ptr bio_; - vio_ptr ssl_con_; - vio_ptr ssl_cip_; - char desc_[100]; - bool open_; - VioSocket* sd_; -}; - -VIO_NS_END - -#endif /* VIO_HAVE_OPENSSL */ diff --git a/vio/VioSSLAcceptorFd.cc b/vio/VioSSLAcceptorFd.cc deleted file mode 100644 index f821685430e..00000000000 --- a/vio/VioSSLAcceptorFd.cc +++ /dev/null @@ -1,4 +0,0 @@ - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif diff --git a/vio/VioSSLFactoriesFd.cc b/vio/VioSSLFactoriesFd.cc deleted file mode 100644 index bd64202770a..00000000000 --- a/vio/VioSSLFactoriesFd.cc +++ /dev/null @@ -1,360 +0,0 @@ -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -#include "vio-global.h" - -#ifdef VIO_HAVE_OPENSSL - -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif - -#include <netinet/in.h> -#include <openssl/x509.h> -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/asn1.h> - -VIO_NS_BEGIN - -#define this_ssl_method my_static_cast(SSL_METHOD*)(this->ssl_method_) -#define this_ssl_context my_static_cast(SSL_CTX*)(this->ssl_context_) -typedef unsigned char* ssl_data_ptr_t; - -static bool ssl_algorithms_added = FALSE; -static bool ssl_error_strings_loaded= FALSE; -static int verify_depth = 0; -static int verify_error = X509_V_OK; - -static int -vio_verify_callback(int ok, X509_STORE_CTX *ctx) -{ - DBUG_ENTER("vio_verify_callback"); - DBUG_PRINT("enter", ("ok=%d, ctx=%p", ok, ctx)); - char buf[256]; - X509* err_cert; - int err,depth; - - err_cert=X509_STORE_CTX_get_current_cert(ctx); - err= X509_STORE_CTX_get_error(ctx); - depth= X509_STORE_CTX_get_error_depth(ctx); - - X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buff)); - if (!ok) - { - DBUG_PRINT("error",("verify error:num=%d:%s\n",err, - X509_verify_cert_error_string(err))); - if (verify_depth >= depth) - { - ok=1; - verify_error=X509_V_OK; - } - else - { - ok=0; - verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG; - } - } - switch (ctx->error) { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256); - DBUG_PRINT("info",("issuer= %s\n",buf)); - break; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - DBUG_PRINT("error", ("notBefore")); - //ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert)); - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - DBUG_PRINT("error", ("notAfter error")); - //ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert)); - break; - } - DBUG_PRINT("exit", ("r=%d", ok)); - DBUG_RETURN(ok); -} - - -static int -vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file) -{ - DBUG_ENTER("vio_set_cert_stuff"); - DBUG_PRINT("enter", ("ctx=%p, cert_file=%p, key_file=%p", - ctx, cert_file, key_file)); - if (cert_file != NULL) - { - if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <= 0) - { - DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file)); - /* FIX stderr */ - ERR_print_errors_fp(stderr); - DBUG_RETURN(0); - } - if (key_file == NULL) - key_file = cert_file; - if (SSL_CTX_use_PrivateKey_file(ctx,key_file, - SSL_FILETYPE_PEM) <= 0) - { - DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file)); - /* FIX stderr */ - ERR_print_errors_fp(stderr); - DBUG_RETURN(0); - } - - /* If we are using DSA, we can copy the parameters from - * the private key */ - /* Now we know that a key and cert have been set against - * the SSL context */ - if (!SSL_CTX_check_private_key(ctx)) - { - DBUG_PRINT("error", ("Private key does not match the certificate public key\n")); - DBUG_RETURN(0); - } - } - DBUG_RETURN(1); -} - -/************************ VioSSLConnectorFd **********************************/ -VioSSLConnectorFd::VioSSLConnectorFd(const char* key_file, - const char* cert_file, - const char* ca_file, - const char* ca_path) -:ssl_context_(0),ssl_method_(0) -{ - DBUG_ENTER("VioSSLConnectorFd::VioSSLConnectorFd"); - DBUG_PRINT("enter", - ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s", - this, key_file, cert_file, ca_path, ca_file)); - - /* FIXME: constants! */ - int verify = SSL_VERIFY_PEER; - - if (!ssl_algorithms_added) - { - DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()")); - ssl_algorithms_added = true; - SSLeay_add_ssl_algorithms(); - } - if (!ssl_error_strings_loaded) - { - DBUG_PRINT("info", ("todo:SSL_load_error_strings()")); - ssl_error_strings_loaded = true; - SSL_load_error_strings(); - } - ssl_method_ = SSLv3_client_method(); - ssl_context_ = SSL_CTX_new(this_ssl_method); - if (ssl_context_ == 0) - { - DBUG_PRINT("error", ("SSL_CTX_new failed")); - report_errors(); - goto ctor_failure; - } - /* - * SSL_CTX_set_options - * SSL_CTX_set_info_callback - * SSL_CTX_set_cipher_list - */ - SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback); - if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1) - { - DBUG_PRINT("error", ("vio_set_cert_stuff failed")); - report_errors(); - goto ctor_failure; - } - if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file,ca_path)==0) - { - DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed")); - if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0) - { - DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed")); - report_errors(); - goto ctor_failure; - } - } - DBUG_VOID_RETURN; -ctor_failure: - DBUG_PRINT("exit", ("there was an error")); - DBUG_VOID_RETURN; -} - -VioSSLConnectorFd::~VioSSLConnectorFd() -{ - DBUG_ENTER("VioSSLConnectorFd::~VioSSLConnectorFd"); - DBUG_PRINT("enter", ("this=%p", this)); - if (ssl_context_!=0) - SSL_CTX_free(this_ssl_context); - DBUG_VOID_RETURN; -} - -VioSSL* VioSSLConnectorFd::connect( int fd) -{ - DBUG_ENTER("VioSSLConnectorFd::connect"); - DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd)); - DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_connect)); -} - -VioSSL* -VioSSLConnectorFd::connect( VioSocket* sd) -{ - DBUG_ENTER("VioSSLConnectorFd::connect"); - DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description())); - DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_connect)); -} - -void -VioSSLConnectorFd::report_errors() -{ - unsigned long l; - const char* file; - const char* data; - int line,flags; - - DBUG_ENTER("VioSSLConnectorFd::report_errors"); - DBUG_PRINT("enter", ("this=%p", this)); - - while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) - { - char buf[200]; - DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), - file,line,(flags&ERR_TXT_STRING)?data:"")) ; - } - DBUG_VOID_RETURN; -} - -/************************ VioSSLAcceptorFd **********************************/ - -VioSSLAcceptorFd::VioSSLAcceptorFd(const char* key_file, - const char* cert_file, - const char* ca_file, - const char* ca_path) - :ssl_context_(0), ssl_method_(0) -{ - DBUG_ENTER("VioSSLAcceptorFd::VioSSLAcceptorFd"); - DBUG_PRINT("enter", - ("this=%p, key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s", - this, key_file, cert_file, ca_path, ca_file)); - - /* FIXME: constants! */ - int verify = (SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT | - SSL_VERIFY_CLIENT_ONCE); - session_id_context_ = static_cast<vio_ptr>(this); - - if (!ssl_algorithms_added) - { - DBUG_PRINT("info", ("todo: SSLeay_add_ssl_algorithms()")); - ssl_algorithms_added = true; - SSLeay_add_ssl_algorithms(); - } - if (!ssl_error_strings_loaded) - { - DBUG_PRINT("info", ("todo: SSL_load_error_strings()")); - ssl_error_strings_loaded = true; - SSL_load_error_strings(); - } - ssl_method_ = SSLv3_server_method(); - ssl_context_ = SSL_CTX_new(this_ssl_method); - if (ssl_context_==0) - { - DBUG_PRINT("error", ("SSL_CTX_new failed")); - report_errors(); - goto ctor_failure; - } - /* - * SSL_CTX_set_quiet_shutdown(ctx,1); - * - */ - SSL_CTX_sess_set_cache_size(this_ssl_context,128); - - /* DH? - */ - SSL_CTX_set_verify(this_ssl_context, verify, vio_verify_callback); - /* - * Double cast needed at least for egcs-1.1.2 to - * supress warnings: - * 1) ANSI C++ blaah implicit cast from 'void*' to 'unsigned char*' - * 2) static_cast from 'void**' to 'unsigned char*' - * Wish I had a copy of standard handy... - */ - SSL_CTX_set_session_id_context(this_ssl_context, - my_static_cast(ssl_data_ptr_t) - (my_static_cast(void*)(&session_id_context_)), - sizeof(session_id_context_)); - - /* - * SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile)); - */ - if (vio_set_cert_stuff(this_ssl_context, cert_file, key_file) == -1) - { - DBUG_PRINT("error", ("vio_set_cert_stuff failed")); - report_errors(); - goto ctor_failure; - } - if (SSL_CTX_load_verify_locations( this_ssl_context, ca_file, ca_path)==0) - { - DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed")); - if (SSL_CTX_set_default_verify_paths(this_ssl_context)==0) - { - DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed")); - report_errors(); - goto ctor_failure; - } - } - DBUG_VOID_RETURN; -ctor_failure: - DBUG_PRINT("exit", ("there was an error")); - DBUG_VOID_RETURN; -} - -VioSSLAcceptorFd::~VioSSLAcceptorFd() -{ - DBUG_ENTER("VioSSLAcceptorFd::~VioSSLAcceptorFd"); - DBUG_PRINT("enter", ("this=%p", this)); - if (ssl_context_!=0) - SSL_CTX_free(this_ssl_context); - DBUG_VOID_RETURN; -} - -VioSSL* -VioSSLAcceptorFd::accept(int fd) -{ - DBUG_ENTER("VioSSLAcceptorFd::accept"); - DBUG_PRINT("enter", ("this=%p, fd=%d", this, fd)); - DBUG_RETURN(new VioSSL(fd, ssl_context_, VioSSL::state_accept)); -} - -VioSSL* -VioSSLAcceptorFd::accept(VioSocket* sd) -{ - DBUG_ENTER("VioSSLAcceptorFd::accept"); - DBUG_PRINT("enter", ("this=%p, sd=%s", this, sd->description())); - DBUG_RETURN(new VioSSL(sd, ssl_context_, VioSSL::state_accept)); -} - -void -VioSSLAcceptorFd::report_errors() -{ - unsigned long l; - const char* file; - const char* data; - int line,flags; - - DBUG_ENTER("VioSSLConnectorFd::report_errors"); - DBUG_PRINT("enter", ("this=%p", this)); - - while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) - { - char buf[200]; - DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), - file,line,(flags&ERR_TXT_STRING)?data:"")) ; - } - DBUG_VOID_RETURN; -} - -VIO_NS_END - -#endif /* VIO_HAVE_OPENSSL */ diff --git a/vio/VioSSLFactoriesFd.h b/vio/VioSSLFactoriesFd.h deleted file mode 100644 index ed5a24f6b4a..00000000000 --- a/vio/VioSSLFactoriesFd.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Wrapper around SSL_CTX. - */ - -#ifdef VIO_HAVE_OPENSSL - -#ifdef __GNUC__ -#pragma interface /* gcc class implementation */ -#endif - -VIO_NS_BEGIN - -class VioSSLAcceptorFd : public VioAcceptorFd -{ -public: - VioSSLAcceptorFd(const char* key_file, - const char* cert_file, - const char* ca_file, - const char* ca_path); - - virtual ~VioSSLAcceptorFd(); - virtual VioSSL* accept(int fd); - virtual VioSSL* accept(VioSocket* sd); -private: - VioSSLAcceptorFd(const VioSSLAcceptorFd& rhs);//undefined - VioSSLAcceptorFd& operator=(const VioSSLAcceptorFd& rhs);//undefined -private: - void report_errors(); - vio_ptr ssl_; - vio_ptr ssl_context_; - vio_ptr ssl_method_; - vio_ptr session_id_context_; -}; - -VIO_NS_END - -/* - * The Factory where Vio's are made! - */ - -class VioSSLConnectorFd : public VioConnectorFd -{ -public: - VioSSLConnectorFd(const char* key_file, - const char* cert_file, - const char* ca_file, - const char* ca_path); - - virtual ~VioSSLConnectorFd(); - virtual VioSSL* connect(int fd); - virtual VioSSL* connect(VioSocket* sd); -private: - VioSSLConnectorFd(const VioSSLConnectorFd& rhs);//undefined - VioSSLConnectorFd& operator=(const VioSSLConnectorFd& rhs);//undefined -private: - void report_errors(); - vio_ptr ssl_context_; - vio_ptr ssl_method_; - vio_ptr ssl_; -}; - -VIO_NS_END - -#endif /* VIO_HAVE_OPENSSL */ diff --git a/vio/VioSocket.cc b/vio/VioSocket.cc deleted file mode 100644 index e8390edb98a..00000000000 --- a/vio/VioSocket.cc +++ /dev/null @@ -1,326 +0,0 @@ -/* Copyright Abandoned 2000 Monty Program KB - - This file is public domain and comes with NO WARRANTY of any kind */ - -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -#include "vio-global.h" -#ifdef __GNUC__ -#pragma implementation // gcc: Class implementation -#endif -#include <assert.h> - -/* - * Probably no need to clean this up - */ - -#ifdef _WIN32 -#include <winsock.h> -#endif -#include <sys/types.h> -#if !defined(__WIN32__) && !defined(MSDOS) -#include <sys/socket.h> -#endif -#if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#if !defined(alpha_linux_port) -#include <netinet/tcp.h> -#endif -#if defined(__EMX__) -#include <sys/ioctl.h> -#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C))) -#undef HAVE_FCNTL -#endif -#endif - -#if defined(MSDOS) || defined(__WIN32__) -#ifdef __WIN32__ -#undef errno -#undef EINTR -#undef EAGAIN -#define errno WSAGetLastError() -#define EINTR WSAEINTR -#define EAGAIN WSAEINPROGRESS -#endif -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK EAGAIN -#endif - -#ifdef __cplusplus -extern "C" { // Because of SCO 3.2V4.2 -#endif -#ifndef __WIN32__ -#include <sys/resource.h> -#ifdef HAVE_SYS_UN_H -#include <sys/un.h> -#endif -#include <netdb.h> -#include <sys/utsname.h> -#endif // __WIN32__ -#ifdef __cplusplus -} -#endif - -VIO_NS_BEGIN - -#define this_ssl_cip my_static_cast(SSL_CIPHER*)(this->ssl_cip_) - -VioSocket::VioSocket(vio_socket sd, enum_vio_type type, bool localhost) -:sd_(sd), localhost_(localhost), fcntl_(0), - fcntl_set_(FALSE), cipher_description_(0) -{ - DBUG_ENTER("VioSocket::VioSocket"); - DBUG_PRINT("enter", ("sd=%d", sd)); - if (type == VIO_TYPE_SOCKET) - sprintf(desc_,"Socket (%d)",sd_); - else - sprintf(desc_,"TCP/IP (%d)",sd_); - DBUG_VOID_RETURN; -} - -VioSocket::~VioSocket() -{ - DBUG_ENTER("VioSocket::~VioSocket"); - DBUG_PRINT("enter", ("sd_=%d", sd_)); - if (sd_>=0) - close(); - DBUG_VOID_RETURN; -} - -bool -VioSocket::is_open() const -{ - return sd_>=0; -} - -int -VioSocket::read(vio_ptr buf, int size) -{ - int r; - DBUG_ENTER("VioSocket::read"); - DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size)); - assert(sd_>=0); -#if defined(MSDOS) || defined(__WIN32__) - r = ::recv(sd_, buf, size,0); -#else - r = ::read(sd_, buf, size); -#endif -#ifndef DBUG_OFF - if ( r < 0) - { - DBUG_PRINT("error", ("Got error %d during read",errno)); - } -#endif /* DBUG_OFF */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - -int -VioSocket::write(vio_ptr buf, int size) -{ - int r; - DBUG_ENTER("VioSocket::write"); - DBUG_PRINT("enter", ("sd_=%d, buf=%p, size=%d", sd_, buf, size)); - assert(sd_>=0); -#if defined(__WIN32__) - r = ::send(sd_, buf, size,0); -#else - r = ::write(sd_, buf, size); -#endif /* __WIN32__ */ -#ifndef DBUG_OFF - if (r < 0) - { - DBUG_PRINT("error", ("Got error %d on write",errno)); - } -#endif /* DBUG_OFF */ - DBUG_RETURN(r); -} - -int -VioSocket::blocking(bool set_blocking_mode) -{ - int r= 0; - DBUG_ENTER("VioSocket::blocking"); - DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode)); - -#if !defined(___WIN32__) && !defined(__EMX__) -#if !defined(NO_FCNTL_NONBLOCK) - assert(sd_>=0); - - int old_fcntl=fcntl_; - if (!fcntl_set_) - { - fcntl_set_ = true; - old_fcntl= fcntl_ = fcntl(F_GETFL); - } - if (set_blocking_mode) - fcntl_&=~O_NONBLOCK; //clear bit - else - fcntl_|=O_NONBLOCK; //set bit - if (old_fcntl != fcntl_) - r = ::fcntl(sd_, F_SETFL, fcntl_); -#endif /* !defined(NO_FCNTL_NONBLOCK) */ -#else /* !defined(__WIN32__) && !defined(__EMX__) */ - { - ulong arg; - int old_fcntl=vio->fcntl_mode; - if (!vio->fcntl_set) - { - vio->fcntl_set = TRUE; - old_fnctl=vio->fcntl_mode=0; - } - if (set_blocking_mode) - { - arg = 0; - fcntl_&=~ O_NONBLOCK; //clear bit - } - else - { - arg = 1; - fcntl_|= O_NONBLOCK; //set bit - } - if (old_fcntl != fcntl_) - r = ioctlsocket(sd_,FIONBIO,(void*)&arg,sizeof(arg)); - } -#endif - DBUG_RETURN(r); -} - -bool -VioSocket::blocking() const -{ - DBUG_ENTER("VioSocket::blocking"); - bool r = !(fcntl_ & O_NONBLOCK); - DBUG_PRINT("exit", ("%d", (int)r)); - DBUG_RETURN(r); -} - -int -VioSocket::fastsend(bool onoff) -{ - int r=0; - DBUG_ENTER("VioSocket::fastsend"); - DBUG_PRINT("enter", ("onoff:%d", (int)onoff)); - assert(sd_>=0); - -#ifdef IPTOS_THROUGHPUT -#ifndef __EMX__ - int tos = IPTOS_THROUGHPUT; - if (!setsockopt(sd_, IPPROTO_IP, IP_TOS, (void*) &tos, sizeof(tos))) -#endif /* !__EMX__ */ - { - int nodelay = 1; - if (setsockopt(sd_, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay, - sizeof(nodelay))) - { - DBUG_PRINT("warning", - ("Couldn't set socket option for fast send")); - r= -1; - } - } -#endif /* IPTOS_THROUGHPUT */ - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(0); -} - - -int -VioSocket::keepalive(bool set_keep_alive) -{ - DBUG_ENTER("VioSocket::keepalive"); - DBUG_PRINT("enter", ("sd_=%d, set_keep_alive=%d", sd_, - (int) set_keep_alive)); - assert(sd_>=0); - uint opt= set_keep_alive ? 1 : 0; - DBUG_RETURN(setsockopt(sd_, SOL_SOCKET, SO_KEEPALIVE, (char*) &opt, - sizeof(opt))); -} - - -bool -VioSocket::should_retry() const -{ - int en = errno; - return en == EAGAIN || en == EINTR || en == EWOULDBLOCK; -} - -int -VioSocket::close() -{ - DBUG_ENTER("VioSocket::close"); - assert(sd_>=0); - int r=0; - if (::shutdown(sd_,2)) - r= -1; - if (::closesocket(sd_)) - r= -1; - if (r) - { - DBUG_PRINT("error", ("close() failed, error: %d",errno)); - /* FIXME: error handling (not critical for MySQL) */ - } - sd_ = -1; - DBUG_RETURN(r); -} - - -int -VioSocket::shutdown(int how) -{ - DBUG_ENTER("VioSocket::shutdown"); - DBUG_PRINT("enter", ("how=%d", how)); - assert(sd_>=0); - int r = ::shutdown(sd_, how); - DBUG_PRINT("exit", ("%d", r)); - DBUG_RETURN(r); -} - - -const char* -VioSocket::description() const -{ - return desc_; -} - - -bool -VioSocket::peer_addr(char *buf) const -{ - DBUG_ENTER("VioSocket::peer_addr"); - DBUG_PRINT("enter", ("sd_=%d", sd_)); - if (localhost_) - { - strmov(buf,"127.0.0.1"); - } - else - { - size_socket addrLen= sizeof(struct sockaddr); - if (getpeername(sd_, my_reinterpret_cast(struct sockaddr *) (&remote_), - &addrLen) != 0) - { - DBUG_PRINT("exit", ("getpeername, error: %d", errno)); - DBUG_RETURN(1); - } - my_inet_ntoa(remote_.sin_addr,buf); - } - DBUG_PRINT("exit", ("addr=%s", buf)); - DBUG_RETURN(0); -} - - -const char* -VioSocket::cipher_description() const -{ - DBUG_ENTER("VioSocket::cipher_description"); - char *r = cipher_description_ ? cipher_description_:""; - DBUG_PRINT("exit", ("name: %s", r)); - DBUG_RETURN(r); -} - -VIO_NS_END diff --git a/vio/VioSocket.h b/vio/VioSocket.h deleted file mode 100644 index e2c6eafa516..00000000000 --- a/vio/VioSocket.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -/* - * Concrete Vio around socket. Doesn't differ much from VioFd. - */ - -#ifdef WIN32 - typedef SOCKET vio_socket; -#else - typedef int vio_socket; -#endif /* WIN32 */ - -VIO_NS_BEGIN - -class VioSSL; -class VioSocket : public Vio -{ -public: - VioSocket(vio_socket sd, bool localhost=true); - virtual ~VioSocket(); - virtual bool is_open() const; - virtual int read(vio_ptr buf, int size); - virtual int write(const vio_ptr buf, int size); - virtual int blocking(bool onoff); - virtual bool blocking() const; - virtual int fastsend(bool onoff=true); - virtual int keepalive(bool onoff); - virtual bool should_retry() const; - virtual int close(); - virtual const char* description() const; - virtual bool peer_addr(char *buf) const; - virtual const char* cipher_description() const; - virtual int vio_errno(); - int shutdown(int how); - -private: - vio_socket sd_; - const bool localhost_; - int fcntl_; - bool fcntl_set_; - char desc_[30]; - mutable struct sockaddr_in local_; - mutable struct sockaddr_in remote_; - mutable char* cipher_description_; - - friend class VioSSL; // he wants to tinker with this->sd_; -}; - -VIO_NS_END - -#endif /* vio_VioSocket_h_ */ - diff --git a/vio/test-ssl b/vio/test-ssl Binary files differnew file mode 100755 index 00000000000..fefa3fce263 --- /dev/null +++ b/vio/test-ssl diff --git a/vio/test-ssl.c b/vio/test-ssl.c new file mode 100644 index 00000000000..f47655c99ab --- /dev/null +++ b/vio/test-ssl.c @@ -0,0 +1,131 @@ +#include <global.h> +#ifdef HAVE_OPENSSL +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" +#include "errmsg.h" +#include <my_dir.h> +#ifndef __GNU_LIBRARY__ +#define __GNU_LIBRARY__ // Skip warnings in getopt.h +#endif +#include <getopt.h> +#include <signal.h> +#include <violite.h> + +const char *VER="0.1"; + + +#ifndef DBUG_OFF +const char *default_dbug_option="d:t:O,-"; +#endif + +void +fatal_error( const char* r) +{ + perror(r); + exit(0); +} + +void +print_usage() +{ + printf("viossl-test: testing SSL virtual IO. Usage:\n"); + printf("viossl-test server-key server-cert client-key client-cert [CAfile] [CApath]\n"); +} + +int +main( int argc, + char** argv) +{ + char* server_key = 0, *server_cert = 0; + char* client_key = 0, *client_cert = 0; + char* ca_file = 0, *ca_path = 0; + int child_pid,sv[2]; + struct st_VioSSLAcceptorFd* ssl_acceptor=0; + struct st_VioSSLConnectorFd* ssl_connector=0; + Vio* client_vio=0, *server_vio=0; + MY_INIT(argv[0]); + DBUG_PROCESS(argv[0]); + DBUG_PUSH(default_dbug_option); + + if (argc<5) + { + print_usage(); + return 1; + } + + server_key = argv[1]; + server_cert = argv[2]; + client_key = argv[3]; + client_cert = argv[4]; + if (argc>5) + ca_file = argv[5]; + if (argc>6) + ca_path = argv[6]; + printf("Server key/cert : %s/%s\n", server_key, server_cert); + printf("Client key/cert : %s/%s\n", client_key, client_cert); + if (ca_file!=0) + printf("CAfile : %s\n", ca_file); + if (ca_path!=0) + printf("CApath : %s\n", ca_path); + + + if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1) + fatal_error("socketpair"); + + ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); + ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path); + + client_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); + client_vio->sd = sv[0]; + client_vio->vioblocking(client_vio,0); + sslconnect(ssl_connector,client_vio); + server_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); + server_vio->sd = sv[1]; + server_vio->vioblocking(client_vio,0); + sslaccept(ssl_acceptor,server_vio); + + printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); + + child_pid = fork(); + if (child_pid==-1) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("fork"); + } + if (child_pid==0) { + //child, therefore, client + char xbuf[100]; + int r = client_vio->read(client_vio,xbuf, sizeof(xbuf)); + if (r<=0) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("client:SSL_read"); + } + xbuf[r] = 0; + printf("client:got %s\n", xbuf); + my_free((gptr)client_vio,MYF(0)); + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + } else { + const char* s = "Huhuhuh"; + int r = server_vio->write(server_vio,(gptr)s, strlen(s)); + if (r<=0) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("server:SSL_write"); + } + my_free((gptr)server_vio,MYF(0)); + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + } + return 0; +} +#else /* HAVE_OPENSSL */ + +int main() { +return 0; +} +#endif /* HAVE_OPENSSL */ + diff --git a/vio/test-sslclient.c b/vio/test-sslclient.c new file mode 100644 index 00000000000..7abac7dad9f --- /dev/null +++ b/vio/test-sslclient.c @@ -0,0 +1,90 @@ +#include <global.h> +#ifdef HAVE_OPENSSL +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" +#include "errmsg.h" +#include <my_dir.h> +#ifndef __GNU_LIBRARY__ +#define __GNU_LIBRARY__ // Skip warnings in getopt.h +#endif +#include <getopt.h> +#include <signal.h> +#include <violite.h> + +const char *VER="0.1"; + + +#ifndef DBUG_OFF +const char *default_dbug_option="d:t:O,-"; +#endif + +void +fatal_error( const char* r) +{ + perror(r); + exit(0); +} + +int +main( int argc __attribute__((unused)), + char** argv) +{ + char client_key[] = "../SSL/client-key.pem", client_cert[] = "../SSL/client-cert.pem"; + char ca_file[] = "../SSL/cacert.pem", *ca_path = 0; + struct st_VioSSLConnectorFd* ssl_connector=0; + struct sockaddr_in sa; + Vio* client_vio=0; + int err; + char xbuf[100]="Ohohhhhoh1234"; + MY_INIT(argv[0]); + DBUG_PROCESS(argv[0]); + DBUG_PUSH(default_dbug_option); + + printf("Client key/cert : %s/%s\n", client_key, client_cert); + if (ca_file!=0) + printf("CAfile : %s\n", ca_file); + if (ca_path!=0) + printf("CApath : %s\n", ca_path); + + ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path); + if(!ssl_connector) { + fatal_error("client:new_VioSSLConnectorFd failed"); + } + + /* ----------------------------------------------- */ + /* Create a socket and connect to server using normal socket calls. */ + + client_vio = vio_new(socket (AF_INET, SOCK_STREAM, 0), VIO_TYPE_TCPIP, TRUE); + + memset (&sa, '\0', sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); /* Server IP */ + sa.sin_port = htons (1111); /* Server Port number */ + + err = connect(client_vio->sd, (struct sockaddr*) &sa, + sizeof(sa)); + + /* ----------------------------------------------- */ + /* Now we have TCP conncetion. Start SSL negotiation. */ + read(client_vio->sd,xbuf, sizeof(xbuf)); + sslconnect(ssl_connector,client_vio); + err = client_vio->read(client_vio,xbuf, sizeof(xbuf)); + if (err<=0) { + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("client:SSL_read"); + } + xbuf[err] = 0; + printf("client:got %s\n", xbuf); + my_free((gptr)client_vio,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + return 0; +} +#else /* HAVE_OPENSSL */ + +int main() { +return 0; +} +#endif /* HAVE_OPENSSL */ + diff --git a/vio/test-sslserver.c b/vio/test-sslserver.c new file mode 100644 index 00000000000..ad4f653ffa6 --- /dev/null +++ b/vio/test-sslserver.c @@ -0,0 +1,141 @@ +#include <global.h> +#ifdef HAVE_OPENSSL +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" +#include "errmsg.h" +#include <my_dir.h> +#ifndef __GNU_LIBRARY__ +#define __GNU_LIBRARY__ // Skip warnings in getopt.h +#endif +#include <getopt.h> +#include <signal.h> +#include <violite.h> + +const char *VER="0.1"; + + +#ifndef DBUG_OFF +const char *default_dbug_option="d:t:O,-"; +#endif + +static void +fatal_error( const char* r) +{ + perror(r); + exit(0); +} + +typedef struct { + int sd; + struct st_VioSSLAcceptorFd* ssl_acceptor; +} TH_ARGS; + +static void +do_ssl_stuff( TH_ARGS* args) +{ + const char* s = "Huhuhuhuuu"; + Vio* server_vio; + int err; + DBUG_ENTER("do_ssl_stuff"); + + server_vio = vio_new(args->sd, VIO_TYPE_TCPIP, TRUE); + + /* ----------------------------------------------- */ + /* TCP connection is ready. Do server side SSL. */ + + err = write(server_vio->sd,(gptr)s, strlen(s)); + sslaccept(args->ssl_acceptor,server_vio); + err = server_vio->write(server_vio,(gptr)s, strlen(s)); + DBUG_VOID_RETURN; +} + +static void* +client_thread( void* arg) +{ + my_thread_init(); + do_ssl_stuff((TH_ARGS*)arg); +} + +int +main( int argc __attribute__((unused)), + char** argv) +{ + char server_key[] = "../SSL/server-key.pem", + server_cert[] = "../SSL/server-cert.pem"; + char ca_file[] = "../SSL/cacert.pem", + *ca_path = 0; + struct st_VioSSLAcceptorFd* ssl_acceptor; + pthread_t th; + TH_ARGS th_args; + + + struct sockaddr_in sa_serv; + struct sockaddr_in sa_cli; + int listen_sd; + int err; + size_t client_len; + int reuseaddr = 1; /* better testing, uh? */ + + MY_INIT(argv[0]); + DBUG_PROCESS(argv[0]); + DBUG_PUSH(default_dbug_option); + + printf("Server key/cert : %s/%s\n", server_key, server_cert); + if (ca_file!=0) + + printf("CAfile : %s\n", ca_file); + if (ca_path!=0) + printf("CApath : %s\n", ca_path); + + th_args.ssl_acceptor = ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); + + /* ----------------------------------------------- */ + /* Prepare TCP socket for receiving connections */ + + listen_sd = socket (AF_INET, SOCK_STREAM, 0); + setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(&reuseaddr)); + + memset (&sa_serv, '\0', sizeof(sa_serv)); + sa_serv.sin_family = AF_INET; + sa_serv.sin_addr.s_addr = INADDR_ANY; + sa_serv.sin_port = htons (1111); /* Server Port number */ + + err = bind(listen_sd, (struct sockaddr*) &sa_serv, + sizeof (sa_serv)); + + /* Receive a TCP connection. */ + + err = listen (listen_sd, 5); + client_len = sizeof(sa_cli); + th_args.sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len); + close (listen_sd); + + printf ("Connection from %lx, port %x\n", + (long)sa_cli.sin_addr.s_addr, sa_cli.sin_port); + + /* ----------------------------------------------- */ + /* TCP connection is ready. Do server side SSL. */ + + err = pthread_create(&th, NULL, client_thread, (void*)&th_args); + DBUG_PRINT("info", ("pthread_create: %d", err)); + pthread_join(th, NULL); + +#if 0 + if (err<=0) { + my_free((gptr)ssl_acceptor,MYF(0)); + fatal_error("server:SSL_write"); + } +#endif /* 0 */ + + my_free((gptr)ssl_acceptor,MYF(0)); + return 0; +} +#else /* HAVE_OPENSSL */ + +int main() { +return 0; +} +#endif /* HAVE_OPENSSL */ + diff --git a/vio/version.cc b/vio/version.cc deleted file mode 100644 index 7c09d431a9d..00000000000 --- a/vio/version.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "vio-global.h" - -extern "C" const char* -vio_version() -{ - return "0.2"; -} diff --git a/vio/vio-global.h b/vio/vio-global.h deleted file mode 100644 index 0c3d279695d..00000000000 --- a/vio/vio-global.h +++ /dev/null @@ -1,33 +0,0 @@ -#include <global.h> - -#if !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL) -#define VIO_HAVE_OPENSSL HAVE_OPENSSL -#endif /* !defined(VIO_HAVE_OPENSSL) && defined(HAVE_OPENSSL) */ - -#include "viotypes.h" -#include "Vio.h" -#include "VioAcceptorFd.h" -#include "VioFd.h" -#include "VioPipe.h" -#include "VioSocket.h" -#ifdef VIO_HAVE_OPENSSL -#include "VioSSL.h" -#include "VioSSLFactoriesFd.h" -#endif /* VIO_HAVE_OPENSSL */ - - -#if VIO_HAVE_NAMESPACES -#define VIO_STD_NS std -#define VIO_STD_NS_USING using namespace std; -#define VIO_NS VirtualIO -#define VIO_NS_BEGIN namespace VIO_NS { -#define VIO_NS_END } -#define VIO_NS_USING using namespace VIO_NS; -#else -#define VIO_STD_NS -#define VIO_STD_NS_USING -#define VIO_NS -#define VIO_NS_BEGIN -#define VIO_NS_END -#define VIO_NS_USING -#endif diff --git a/vio/vio.c b/vio/vio.c new file mode 100644 index 00000000000..96cb0c31ef6 --- /dev/null +++ b/vio/vio.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 */ + +/* + Note that we can't have assertion on file descriptors; The reason for + this is that during mysql shutdown, another thread can close a file + we are working on. In this case we should just return read errors from + the file descriptior. +*/ + +#define DONT_MAP_VIO +#include <global.h> +#include <mysql_com.h> +#include <violite.h> + +#include <errno.h> +#include <assert.h> +#include <my_sys.h> +#include <my_net.h> +#include <m_string.h> +#ifdef HAVE_POLL +#include <sys/poll.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if defined(__EMX__) +#define ioctlsocket ioctl +#endif /* defined(__EMX__) */ + +#if defined(MSDOS) || defined(__WIN__) +#ifdef __WIN__ +#undef errno +#undef EINTR +#undef EAGAIN +#define errno WSAGetLastError() +#define EINTR WSAEINTR +#define EAGAIN WSAEINPROGRESS +#endif /* __WIN__ */ +#define O_NONBLOCK 1 /* For emulation of fcntl() */ +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + + +/* + * Helper to fill most of the Vio* with defaults. + */ + +void vio_reset(Vio* vio, enum enum_vio_type type, + my_socket sd, HANDLE hPipe, + my_bool localhost) +{ + DBUG_ENTER("vio_reset"); + DBUG_PRINT("enter", ("type=%d sd=%d localhost=%d", type, sd, localhost)); + + bzero((char*) vio, sizeof(*vio)); + vio->type = type; + vio->sd = sd; + vio->hPipe = hPipe; + vio->localhost= localhost; +#ifdef HAVE_VIO +#ifdef HAVE_OPENSSL + if (type == VIO_TYPE_SSL) + { + vio->viodelete =vio_ssl_delete; + vio->vioerrno =vio_ssl_errno; + vio->read =vio_ssl_read; + vio->write =vio_ssl_write; + vio->fastsend =vio_ssl_fastsend; + vio->viokeepalive =vio_ssl_keepalive; + vio->should_retry =vio_ssl_should_retry; + vio->vioclose =vio_ssl_close; + vio->peer_addr =vio_ssl_peer_addr; + vio->in_addr =vio_ssl_in_addr; + vio->poll_read =vio_ssl_poll_read; + vio->vioblocking =vio_blocking; + vio->is_blocking =vio_is_blocking; + } + else /* default is VIO_TYPE_TCPIP */ +#endif /* HAVE_OPENSSL */ + { + vio->viodelete =vio_delete; + vio->vioerrno =vio_errno; + vio->read =vio_read; + vio->write =vio_write; + vio->fastsend =vio_fastsend; + vio->viokeepalive =vio_keepalive; + vio->should_retry =vio_should_retry; + vio->vioclose =vio_close; + vio->peer_addr =vio_peer_addr; + vio->in_addr =vio_in_addr; + vio->poll_read =vio_poll_read; + vio->vioblocking =vio_blocking; + vio->is_blocking =vio_is_blocking; + } +#endif /* HAVE_VIO */ + DBUG_VOID_RETURN; +} + +/* Open the socket or TCP/IP connection and read the fnctl() status */ + +Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) +{ + Vio *vio; + DBUG_ENTER("vio_new"); + DBUG_PRINT("enter", ("sd=%d", sd)); + if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) + { + vio_reset(vio, type, sd, 0, localhost); + sprintf(vio->desc, + (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"), + vio->sd); +#if !defined(___WIN__) && !defined(__EMX__) +#if !defined(NO_FCNTL_NONBLOCK) + vio->fcntl_mode = fcntl(sd, F_GETFL); +#elif defined(HAVE_SYS_IOCTL_H) /* hpux */ + /* Non blocking sockets doesn't work good on HPUX 11.0 */ + (void) ioctl(sd,FIOSNBIO,0); +#endif +#else /* !defined(__WIN__) && !defined(__EMX__) */ + { + /* set to blocking mode by default */ + ulong arg=0, r; + r = ioctlsocket(sd,FIONBIO,(void*) &arg, sizeof(arg)); + } +#endif + } + DBUG_RETURN(vio); +} + + +#ifdef __WIN__ + +Vio *vio_new_win32pipe(HANDLE hPipe) +{ + Vio *vio; + DBUG_ENTER("vio_new_handle"); + if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) + { + vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE); + strmov(vio->desc, "named pipe"); + } + DBUG_RETURN(vio); +} + +#endif diff --git a/vio/vioelitexx.cc b/vio/vioelitexx.cc deleted file mode 100644 index 0eac28eaf55..00000000000 --- a/vio/vioelitexx.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright Abandoned 2000 Monty Program KB - This file is public domain and comes with NO WARRANTY of any kind */ - -/* - * Renamed of violite.cc to violitexx.cc because of clashes - * with violite.c - * This file implements the same functions as in violite.c, but now using - * the Vio class - */ - -#include "vio-global.h" - -Vio* -vio_new(my_socket sd, enum_vio_type type, my_bool localhost) -{ - return my_reinterpret_cast(Vio*) (new VioSocket(sd, type, localhost)); -} - - -#ifdef __WIN32__ -Vio -*vio_new_win32pipe(HANDLE hPipe) -{ - return my_reinterpret_cast(Vio*) (new VioPipe(hPipe)); -} -#endif diff --git a/vio/violite.h b/vio/violite.h deleted file mode 100644 index fc480f59db1..00000000000 --- a/vio/violite.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright Abandoned 2000 Monty Program KB - This file is public domain and comes with NO WARRANTY of any kind */ - -/* - * Vio Lite. - * Purpose: include file for Vio that will work with C and C++ - */ - -#ifndef vio_violite_h_ -#define vio_violite_h_ - -#include "my_net.h" /* needed because of struct in_addr */ - -#ifdef HAVE_VIO -#include <Vio.h> /* Full VIO interface */ -#else - -/* Simple vio interface in C; The functions are implemented in violite.c */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef Vio_defined -#define Vio_defined -struct st_vio; /* Only C */ -typedef struct st_vio Vio; -#endif - -enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, - VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL}; - -Vio* vio_new(my_socket sd, - enum enum_vio_type type, - my_bool localhost); -#ifdef __WIN__ -Vio* vio_new_win32pipe(HANDLE hPipe); -#endif -void vio_delete(Vio* vio); - -/* - * vio_read and vio_write should have the same semantics - * as read(2) and write(2). - */ -int vio_read( Vio* vio, - gptr buf, int size); -int vio_write( Vio* vio, - const gptr buf, - int size); -/* - * Whenever the socket is set to blocking mode or not. - */ -int vio_blocking( Vio* vio, - my_bool onoff); -my_bool vio_is_blocking( Vio* vio); -/* - * setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible. - */ -int vio_fastsend( Vio* vio, - my_bool onoff); -/* - * setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible. - */ -int vio_keepalive( Vio* vio, - my_bool onoff); -/* - * Whenever we should retry the last read/write operation. - */ -my_bool vio_should_retry( Vio* vio); -/* - * When the workday is over... - */ -int vio_close( Vio* vio); -/* - * Short text description of the socket for those, who are curious.. - */ -const char* vio_description( Vio* vio); - -/* Return the type of the connection */ - enum enum_vio_type vio_type(Vio* vio); - -/* Return last error number */ -int vio_errno(Vio *vio); - -/* Get socket number */ -my_socket vio_fd(Vio *vio); - -/* - * Remote peer's address and name in text form. - */ -my_bool vio_peer_addr(Vio * vio, char *buf); - -/* Remotes in_addr */ - -void vio_in_addr(Vio *vio, struct in_addr *in); - -#ifdef __cplusplus -} -#endif -#endif /* HAVE_VIO */ -#endif /* vio_violite_h_ */ diff --git a/libmysql/violite.c b/vio/viosocket.c index 0d96c71969c..d5573cdfa64 100644 --- a/libmysql/violite.c +++ b/vio/viosocket.c @@ -22,9 +22,9 @@ the file descriptior. */ +#define DONT_MAP_VIO #include <global.h> - -#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */ +#include <mysql_com.h> #include <errno.h> #include <assert.h> @@ -39,100 +39,30 @@ #include <sys/ioctl.h> #endif -#if defined(__EMX__) || defined(OS2) +#if defined(__EMX__) #define ioctlsocket ioctl #endif /* defined(__EMX__) */ #if defined(MSDOS) || defined(__WIN__) +#ifdef __WIN__ +#undef errno +#undef EINTR +#undef EAGAIN +#define errno WSAGetLastError() +#define EINTR WSAEINTR +#define EAGAIN WSAEINPROGRESS +#endif /* __WIN__ */ #define O_NONBLOCK 1 /* For emulation of fcntl() */ #endif #ifndef EWOULDBLOCK -#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN +#define EWOULDBLOCK EAGAIN #endif #ifndef __WIN__ #define HANDLE void * #endif -struct st_vio -{ - my_socket sd; /* my_socket - real or imaginary */ - HANDLE hPipe; - my_bool localhost; /* Are we from localhost? */ - int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ - struct sockaddr_in local; /* Local internet address */ - struct sockaddr_in remote; /* Remote internet address */ - enum enum_vio_type type; /* Type of connection */ - char desc[30]; /* String description */ -}; - -typedef void *vio_ptr; -typedef char *vio_cstring; - -/* - * Helper to fill most of the Vio* with defaults. - */ - -static void vio_reset(Vio* vio, enum enum_vio_type type, - my_socket sd, HANDLE hPipe, - my_bool localhost) -{ - bzero((char*) vio, sizeof(*vio)); - vio->type = type; - vio->sd = sd; - vio->hPipe = hPipe; - vio->localhost= localhost; -} - -/* Open the socket or TCP/IP connection and read the fnctl() status */ - -Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost) -{ - Vio *vio; - DBUG_ENTER("vio_new"); - DBUG_PRINT("enter", ("sd=%d", sd)); - if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) - { - vio_reset(vio, type, sd, 0, localhost); - sprintf(vio->desc, - (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"), - vio->sd); -#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) -#if !defined(NO_FCNTL_NONBLOCK) - vio->fcntl_mode = fcntl(sd, F_GETFL); -#elif defined(HAVE_SYS_IOCTL_H) /* hpux */ - /* Non blocking sockets doesn't work good on HPUX 11.0 */ - (void) ioctl(sd,FIOSNBIO,0); -#endif -#else /* !defined(__WIN__) && !defined(__EMX__) */ - { - /* set to blocking mode by default */ - ulong arg=0, r; - r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg)); - } -#endif - } - DBUG_RETURN(vio); -} - - -#ifdef __WIN__ - -Vio *vio_new_win32pipe(HANDLE hPipe) -{ - Vio *vio; - DBUG_ENTER("vio_new_handle"); - if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) - { - vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE); - strmov(vio->desc, "named pipe"); - } - DBUG_RETURN(vio); -} - -#endif - -void vio_delete(Vio * vio) +void vio_delete(Vio* vio) { /* It must be safe to delete null pointers. */ /* This matches the semantics of C++'s delete operator. */ @@ -146,7 +76,7 @@ void vio_delete(Vio * vio) int vio_errno(Vio *vio __attribute__((unused))) { - return socket_errno; /* On Win32 this mapped to WSAGetLastError() */ + return errno; /* On Win32 this mapped to WSAGetLastError() */ } @@ -155,17 +85,12 @@ int vio_read(Vio * vio, gptr buf, int size) int r; DBUG_ENTER("vio_read"); DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size)); -#if defined( __WIN__) || defined(OS2) +#ifdef __WIN__ if (vio->type == VIO_TYPE_NAMEDPIPE) { DWORD length; -#ifdef OS2 - if (!DosRead((HFILE)vio->hPipe, buf, size, &length)) - DBUG_RETURN(-1); -#else if (!ReadFile(vio->hPipe, buf, size, &length, NULL)) DBUG_RETURN(-1); -#endif DBUG_RETURN(length); } r = recv(vio->sd, buf, size,0); @@ -176,7 +101,7 @@ int vio_read(Vio * vio, gptr buf, int size) #ifndef DBUG_OFF if (r < 0) { - DBUG_PRINT("vio_error", ("Got error %d during read",socket_errno)); + DBUG_PRINT("vio_error", ("Got error %d during read",errno)); } #endif /* DBUG_OFF */ DBUG_PRINT("exit", ("%d", r)); @@ -189,17 +114,12 @@ int vio_write(Vio * vio, const gptr buf, int size) int r; DBUG_ENTER("vio_write"); DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size)); -#if defined( __WIN__) || defined(OS2) +#ifdef __WIN__ if ( vio->type == VIO_TYPE_NAMEDPIPE) { DWORD length; -#ifdef OS2 - if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length)) - DBUG_RETURN(-1); -#else if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL)) DBUG_RETURN(-1); -#endif DBUG_RETURN(length); } r = send(vio->sd, buf, size,0); @@ -209,7 +129,7 @@ int vio_write(Vio * vio, const gptr buf, int size) #ifndef DBUG_OFF if (r < 0) { - DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno)); + DBUG_PRINT("vio_error", ("Got error on write: %d",errno)); } #endif /* DBUG_OFF */ DBUG_PRINT("exit", ("%d", r)); @@ -223,7 +143,8 @@ int vio_blocking(Vio * vio, my_bool set_blocking_mode) DBUG_ENTER("vio_blocking"); DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode)); -#if !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) +#if !defined(HAVE_OPENSSL) +#if !defined(___WIN__) && !defined(__EMX__) #if !defined(NO_FCNTL_NONBLOCK) if (vio->sd >= 0) @@ -258,6 +179,8 @@ int vio_blocking(Vio * vio, my_bool set_blocking_mode) r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg)); } #endif /* !defined(__WIN__) && !defined(__EMX__) */ +#endif /* !defined (HAVE_OPENSSL) */ + DBUG_PRINT("exit", ("return %d", r)); DBUG_RETURN(r); } @@ -319,8 +242,8 @@ int vio_keepalive(Vio* vio, my_bool set_keep_alive) my_bool vio_should_retry(Vio * vio __attribute__((unused))) { - int en = socket_errno; - return en == SOCKET_EAGAIN || en == SOCKET_EINTR || en == SOCKET_EWOULDBLOCK; + int en = errno; + return en == EAGAIN || en == EINTR || en == EWOULDBLOCK; } @@ -348,7 +271,7 @@ int vio_close(Vio * vio) } if (r) { - DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno)); + DBUG_PRINT("vio_error", ("close() failed, error: %d",errno)); /* FIXME: error handling (not critical for MySQL) */ } vio->type= VIO_CLOSED; @@ -387,7 +310,7 @@ my_bool vio_peer_addr(Vio * vio, char *buf) if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)), &addrLen) != 0) { - DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno)); + DBUG_PRINT("exit", ("getpeername, error: %d", errno)); DBUG_RETURN(1); } my_inet_ntoa(vio->remote.sin_addr,buf); @@ -428,5 +351,3 @@ my_bool vio_poll_read(Vio *vio,uint timeout) DBUG_RETURN(fds.revents & POLLIN ? 0 : 1); #endif } - -#endif /* HAVE_VIO */ diff --git a/vio/viossl.c b/vio/viossl.c new file mode 100644 index 00000000000..8b1a51845be --- /dev/null +++ b/vio/viossl.c @@ -0,0 +1,477 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + +/* + Note that we can't have assertion on file descriptors; The reason for + this is that during mysql shutdown, another thread can close a file + we are working on. In this case we should just return read errors from + the file descriptior. +*/ + +#include <global.h> + +#ifdef HAVE_OPENSSL + +#include <mysql_com.h> + +#include <errno.h> +#include <assert.h> +#include <violite.h> +#include <my_sys.h> +#include <my_net.h> +#include <m_string.h> +#ifdef HAVE_POLL +#include <sys/poll.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if defined(__EMX__) +#define ioctlsocket ioctl +#endif /* defined(__EMX__) */ + +#if defined(MSDOS) || defined(__WIN__) +#ifdef __WIN__ +#undef errno +#undef EINTR +#undef EAGAIN +#define errno WSAGetLastError() +#define EINTR WSAEINTR +#define EAGAIN WSAEINPROGRESS +#endif /* __WIN__ */ +#define O_NONBLOCK 1 /* For emulation of fcntl() */ +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +#ifndef __WIN__ +#define HANDLE void * +#endif + +static void +report_errors() +{ + unsigned long l; + const char* file; + const char* data; + int line,flags, any_ssl_error = 0; + DBUG_ENTER("report_errors"); + + while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) + { + char buf[200]; + any_ssl_error = 1; + DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), + file,line,(flags&ERR_TXT_STRING)?data:"")) ; + } + if (!any_ssl_error) { + DBUG_PRINT("info", ("No OpenSSL errors.")); + } + DBUG_PRINT("info", ("BTW, errno=%d", errno)); + DBUG_VOID_RETURN; +} + + +void vio_ssl_delete(Vio * vio) +{ + /* It must be safe to delete null pointers. */ + /* This matches the semantics of C++'s delete operator. */ + if (vio) + { + if (vio->type != VIO_CLOSED) + vio_close(vio); + my_free((gptr) vio,MYF(0)); + } +} + +int vio_ssl_errno(Vio *vio __attribute__((unused))) +{ + return errno; /* On Win32 this mapped to WSAGetLastError() */ +} + + +int vio_ssl_read(Vio * vio, gptr buf, int size) +{ + int r; + DBUG_ENTER("vio_ssl_read"); + DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d, ssl_=%p", + vio->sd, buf, size, vio->ssl_)); + +#ifndef DBUG_OFF + errno = 0; +#endif /* DBUG_OFF */ + r = SSL_read(vio->ssl_, buf, size); +#ifndef DBUG_OFF + if ( r< 0) + report_errors(); +#endif /* DBUG_OFF */ + DBUG_PRINT("exit", ("%d", r)); + DBUG_RETURN(r); +} + + +int vio_ssl_write(Vio * vio, const gptr buf, int size) +{ + int r; + DBUG_ENTER("vio_ssl_write"); + DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size)); + +#ifndef DBUG_OFF + errno = 0; +#endif /* DBUG_OFF */ + r = SSL_write(vio->ssl_, buf, size); +#ifndef DBUG_OFF + if (r<0) + report_errors(); +#endif /* DBUG_OFF */ + DBUG_PRINT("exit", ("%d", r)); + DBUG_RETURN(r); +} + + +int vio_ssl_fastsend(Vio * vio __attribute__((unused))) +{ + int r=0; + DBUG_ENTER("vio_ssl_fastsend"); + +#ifdef IPTOS_THROUGHPUT + { +#ifndef __EMX__ + int tos = IPTOS_THROUGHPUT; + if (!setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos))) +#endif /* !__EMX__ */ + { + int nodelay = 1; + if (setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay, + sizeof(nodelay))) { + DBUG_PRINT("warning", + ("Couldn't set socket option for fast send")); + r= -1; + } + } + } +#endif /* IPTOS_THROUGHPUT */ + DBUG_PRINT("exit", ("%d", r)); + DBUG_RETURN(r); +} + +int vio_ssl_keepalive(Vio* vio, my_bool set_keep_alive) +{ + int r=0; + uint opt = 0; + DBUG_ENTER("vio_ssl_keepalive"); + DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int) + set_keep_alive)); + if (vio->type != VIO_TYPE_NAMEDPIPE) + { + if (set_keep_alive) + opt = 1; + r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, + sizeof(opt)); + } + DBUG_RETURN(r); +} + + +my_bool +vio_ssl_should_retry(Vio * vio __attribute__((unused))) +{ + int en = errno; + return en == EAGAIN || en == EINTR || en == EWOULDBLOCK; +} + + +int vio_ssl_close(Vio * vio) +{ + int r; + DBUG_ENTER("vio_ssl_close"); + r=0; + if (vio->ssl_) + { + r = SSL_shutdown(vio->ssl_); + SSL_free(vio->ssl_); + vio->ssl_= 0; + vio->bio_ = 0; + } + if (shutdown(vio->sd,2)) + r= -1; + if (closesocket(vio->sd)) + r= -1; + if (r) + { + DBUG_PRINT("error", ("close() failed, error: %d",errno)); + report_errors(); + /* FIXME: error handling (not critical for MySQL) */ + } + vio->type= VIO_CLOSED; + vio->sd= -1; + DBUG_RETURN(r); +} + + +const char *vio_ssl_description(Vio * vio) +{ + return vio->desc; +} + +enum enum_vio_type vio_ssl_type(Vio* vio) +{ + return vio->type; +} + +my_socket vio_ssl_fd(Vio* vio) +{ + return vio->sd; +} + + +my_bool vio_ssl_peer_addr(Vio * vio, char *buf) +{ + DBUG_ENTER("vio_ssl_peer_addr"); + DBUG_PRINT("enter", ("sd=%d", vio->sd)); + if (vio->localhost) + { + strmov(buf,"127.0.0.1"); + } + else + { + size_socket addrLen = sizeof(struct sockaddr); + if (getpeername(vio->sd, (struct sockaddr *) (& (vio->remote)), + &addrLen) != 0) + { + DBUG_PRINT("exit", ("getpeername, error: %d", errno)); + DBUG_RETURN(1); + } + /* FIXME */ +/* my_inet_ntoa(vio->remote.sin_addr,buf); */ + } + DBUG_PRINT("exit", ("addr=%s", buf)); + DBUG_RETURN(0); +} + + +void vio_ssl_in_addr(Vio *vio, struct in_addr *in) +{ + DBUG_ENTER("vio_ssl_in_addr"); + if (vio->localhost) + bzero((char*) in, sizeof(*in)); /* This should never be executed */ + else + *in=vio->remote.sin_addr; + DBUG_VOID_RETURN; +} + + +/* Return 0 if there is data to be read */ + +my_bool vio_ssl_poll_read(Vio *vio,uint timeout) +{ +#ifndef HAVE_POLL + return 0; +#else + struct pollfd fds; + int res; + DBUG_ENTER("vio_ssl_poll"); + fds.fd=vio->sd; + fds.events=POLLIN; + fds.revents=0; + if ((res=poll(&fds,1,(int) timeout*1000)) <= 0) + { + DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */ + } + DBUG_RETURN(fds.revents & POLLIN ? 0 : 1); +#endif +} + +void sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio) +{ + X509* client_cert; + char *str; + int i; +// const int blocking = vio_is_blocking(vio); + DBUG_ENTER("sslaccept"); + DBUG_PRINT("enter", ("sd=%d ptr=%p", vio->sd,ptr)); + vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE); + vio->ssl_=0; + vio->open_=FALSE; + if (!(vio->ssl_ = SSL_new(ptr->ssl_context_))) + { + DBUG_PRINT("error", ("SSL_new failure")); + report_errors(); + DBUG_VOID_RETURN; + } + DBUG_PRINT("info", ("ssl_=%p",vio->ssl_)); + vio_blocking(vio, FALSE); + SSL_set_fd(vio->ssl_,vio->sd); + SSL_set_accept_state(vio->ssl_); + + /* FIXME possibly infinite loop */ + while (SSL_is_init_finished(vio->ssl_)) { + DBUG_PRINT("info",("SSL_is_init_finished(vio->ssl_) is not 1")); + if((i=SSL_do_handshake(vio->ssl_))!=SSL_ERROR_NONE) + { + DBUG_PRINT("info",("*** errno %d",errno)); + switch (SSL_get_error(vio->ssl_,i)) + { + case SSL_ERROR_NONE: + DBUG_PRINT("info",("SSL_ERROR_NONE: handshake finished")); + break; + case SSL_ERROR_SSL: + DBUG_PRINT("info",("SSL_ERROR_SSL: SSL protocol error ")); + break; + case SSL_ERROR_WANT_CONNECT: + DBUG_PRINT("info",("SSL_ERROR_WANT_CONNECT:If you are doing non-blocking connects call again when the connection is established")); + break; + case SSL_ERROR_WANT_READ: + DBUG_PRINT("info",("SSL_ERROR_WANT_READ: if non-blocking etc, call again when data is available")); + break; + case SSL_ERROR_WANT_WRITE: + DBUG_PRINT("info",("SSL_ERROR_WANT_WRITE: if non-blocking etc, call again when data is available to write")); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + DBUG_PRINT("info",("SSL_ERROR_WANT_X509_LOOKUP: /* not used yet but could be :-) */")); + break; + case SSL_ERROR_SYSCALL: + DBUG_PRINT("info",("SSL_ERROR_SYSCALL: An error than the error code can be found in errno (%d)",errno)); + break; + case SSL_ERROR_ZERO_RETURN: + DBUG_PRINT("info",("SSL_ERROR_ZERO_RETURN: 0 returned on the read, normally means the socket is closed :-) */")); + break; + default: + DBUG_PRINT("info",("Unknown SSL error returned")); + break; + } + } + usleep(100); + } + vio->open_ = TRUE; +#ifndef DBUF_OFF + DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'" + ,SSL_get_cipher_name(vio->ssl_))); + client_cert = SSL_get_peer_certificate (vio->ssl_); + if (client_cert != NULL) { + DBUG_PRINT("info",("Client certificate:")); + str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); + DBUG_PRINT("info",("\t subject: %s", str)); + free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); + DBUG_PRINT("info",("\t issuer: %s", str)); + free (str); + + /* We could do all sorts of certificate verification stuff here before + * deallocating the certificate. */ + + X509_free (client_cert); + } else + DBUG_PRINT("info",("Client does not have certificate.")); +#endif + DBUG_VOID_RETURN; +} + +void sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio) +{ + char *str; +// char s[]="abc"; +int i; + X509* server_cert; + const int blocking = vio_is_blocking(vio); + DBUG_ENTER("sslconnect"); + DBUG_PRINT("enter", ("sd=%d ptr=%p ctx: %p", vio->sd,ptr,ptr->ssl_context_)); + vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE); + + vio->ssl_=0; + vio->open_=FALSE; + if (!(vio->ssl_ = SSL_new(ptr->ssl_context_))) + { + DBUG_PRINT("error", ("SSL_new failure")); + report_errors(); + DBUG_VOID_RETURN; + } + DBUG_PRINT("info", ("ssl_=%p",vio->ssl_)); + vio_blocking(vio, FALSE); + SSL_set_fd (vio->ssl_, vio->sd); + SSL_set_connect_state(vio->ssl_); + + /* FIXME possibly infinite loop */ + while (SSL_is_init_finished(vio->ssl_)) { + DBUG_PRINT("info",("SSL_is_init_finished(vio->ssl_) is not 1")); + if((i=SSL_do_handshake(vio->ssl_))!=SSL_ERROR_NONE) + { + DBUG_PRINT("info",("*** errno %d",errno)); + switch (SSL_get_error(vio->ssl_,i)) + { + case SSL_ERROR_NONE: + DBUG_PRINT("info",("SSL_ERROR_NONE: handshake finished")); + break; + case SSL_ERROR_SSL: + DBUG_PRINT("info",("SSL_ERROR_SSL: SSL protocol error ")); + break; + case SSL_ERROR_WANT_CONNECT: + DBUG_PRINT("info",("SSL_ERROR_WANT_CONNECT:If you are doing non-blocking connects call again when the connection is established")); + break; + case SSL_ERROR_WANT_READ: + DBUG_PRINT("info",("SSL_ERROR_WANT_READ: if non-blocking etc, call again when data is available")); + break; + case SSL_ERROR_WANT_WRITE: + DBUG_PRINT("info",("SSL_ERROR_WANT_WRITE: if non-blocking etc, call again when data is available to write")); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + DBUG_PRINT("info",("SSL_ERROR_WANT_X509_LOOKUP: /* not used yet but could be :-) */")); + break; + case SSL_ERROR_SYSCALL: + DBUG_PRINT("info",("SSL_ERROR_SYSCALL: An error than the error code can be found in errno (%d)",errno)); + break; + case SSL_ERROR_ZERO_RETURN: + DBUG_PRINT("info",("SSL_ERROR_ZERO_RETURN: 0 returned on the read, normally means the socket is closed :-) */")); + break; + default: + DBUG_PRINT("info",("Unknown SSL error returned")); + break; + } + } + usleep(100); + } + vio->open_ = TRUE; +#ifndef DBUG_OFF + DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'" + ,SSL_get_cipher_name(vio->ssl_))); + server_cert = SSL_get_peer_certificate (vio->ssl_); + if (server_cert != NULL) { + DBUG_PRINT("info",("Server certificate:")); + str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0); + DBUG_PRINT("info",("\t subject: %s", str)); + free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0); + DBUG_PRINT("info",("\t issuer: %s", str)); + free (str); + + /* We could do all sorts of certificate verification stuff here before + * deallocating the certificate. */ + + X509_free (server_cert); + } else + DBUG_PRINT("info",("Server does not have certificate.")); +#endif + vio_blocking(vio, blocking); + DBUG_VOID_RETURN; +} + + +#endif /* HAVE_OPENSSL */ diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c new file mode 100644 index 00000000000..ebfb860d0ca --- /dev/null +++ b/vio/viosslfactories.c @@ -0,0 +1,350 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA */ + + +#include <global.h> + +#ifdef HAVE_OPENSSL + +#include <my_sys.h> +#include <mysql_com.h> +#include <violite.h> + + +static bool ssl_algorithms_added = FALSE; +static bool ssl_error_strings_loaded= FALSE; +static int verify_depth = 0; +static int verify_error = X509_V_OK; + +static unsigned char dh512_p[]={ + 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, + 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F, + 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3, + 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12, + 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C, + 0x47,0x74,0xE8,0x33, +}; +static unsigned char dh512_g[]={ + 0x02, +}; + +static DH *get_dh512(void) +{ + DH *dh=NULL; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); + dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return(NULL); + return(dh); +} + +static void +report_errors() +{ + unsigned long l; + const char* file; + const char* data; + int line,flags; + + DBUG_ENTER("report_errors"); + + while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) + { + char buf[200]; + DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), + file,line,(flags&ERR_TXT_STRING)?data:"")) ; + } + DBUG_VOID_RETURN; +} + + +static int +vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file) +{ + DBUG_ENTER("vio_set_cert_stuff"); + DBUG_PRINT("enter", ("ctx=%p, cert_file=%s, key_file=%s", + ctx, cert_file, key_file)); + if (cert_file != NULL) + { + if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <= 0) + { + DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file)); + /* FIX stderr */ + ERR_print_errors_fp(stderr); + DBUG_RETURN(0); + } + if (key_file == NULL) + key_file = cert_file; + if (SSL_CTX_use_PrivateKey_file(ctx,key_file, + SSL_FILETYPE_PEM) <= 0) + { + DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file)); + /* FIX stderr */ + ERR_print_errors_fp(stderr); + DBUG_RETURN(0); + } + + /* If we are using DSA, we can copy the parameters from + * the private key */ + /* Now we know that a key and cert have been set against + * the SSL context */ + if (!SSL_CTX_check_private_key(ctx)) + { + DBUG_PRINT("error", ("Private key does not match the certificate public key\n")); + DBUG_RETURN(0); + } + } + DBUG_RETURN(1); +} + + +static int +vio_verify_callback(int ok, X509_STORE_CTX *ctx) +{ + char buf[256]; + X509* err_cert; + int err,depth; + + DBUG_ENTER("vio_verify_callback"); + DBUG_PRINT("enter", ("ok=%d, ctx=%p", ok, ctx)); + err_cert=X509_STORE_CTX_get_current_cert(ctx); + err= X509_STORE_CTX_get_error(ctx); + depth= X509_STORE_CTX_get_error_depth(ctx); + + X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf)); + if (!ok) + { + DBUG_PRINT("error",("verify error:num=%d:%s\n",err, + X509_verify_cert_error_string(err))); + if (verify_depth >= depth) + { + ok=1; + verify_error=X509_V_OK; + } + else + { + ok=0; + verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG; + } + } + switch (ctx->error) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,256); + DBUG_PRINT("info",("issuer= %s\n",buf)); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + DBUG_PRINT("error", ("notBefore")); + /*ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert));*/ + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + DBUG_PRINT("error", ("notAfter error")); + /*ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert));*/ + break; + } + DBUG_PRINT("exit", ("r=%d", ok)); + DBUG_RETURN(ok); +} + + +/************************ VioSSLConnectorFd **********************************/ +struct st_VioSSLConnectorFd* new_VioSSLConnectorFd(const char* key_file, + const char* cert_file, + const char* ca_file, + const char* ca_path) +{ + int verify = SSL_VERIFY_PEER; + struct st_VioSSLConnectorFd* ptr; + DH *dh=NULL; + DBUG_ENTER("new_VioSSLConnectorFd"); + DBUG_PRINT("enter", + ("key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s", + key_file, cert_file, ca_path, ca_file)); + ptr=(struct st_VioSSLConnectorFd*)my_malloc(sizeof(struct st_VioSSLConnectorFd),MYF(0)); + ptr->ssl_context_=0; + ptr->ssl_method_=0; + /* FIXME: constants! */ + + if (!ssl_algorithms_added) + { + DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()")); + ssl_algorithms_added = TRUE; + OpenSSL_add_all_algorithms(); + } + if (!ssl_error_strings_loaded) + { + DBUG_PRINT("info", ("todo:SSL_load_error_strings()")); + ssl_error_strings_loaded = TRUE; + SSL_load_error_strings(); + } + ptr->ssl_method_ = TLSv1_client_method(); + ptr->ssl_context_ = SSL_CTX_new(ptr->ssl_method_); + DBUG_PRINT("info", ("ssl_context_: %p",ptr->ssl_context_)); + if (ptr->ssl_context_ == 0) + { + DBUG_PRINT("error", ("SSL_CTX_new failed")); + report_errors(); + goto ctor_failure; + } + /* + * SSL_CTX_set_options + * SSL_CTX_set_info_callback + * SSL_CTX_set_cipher_list + */ + SSL_CTX_set_verify(ptr->ssl_context_, verify, vio_verify_callback); + if (vio_set_cert_stuff(ptr->ssl_context_, cert_file, key_file) == -1) + { + DBUG_PRINT("error", ("vio_set_cert_stuff failed")); + report_errors(); + goto ctor_failure; + } + if (SSL_CTX_load_verify_locations( ptr->ssl_context_, ca_file,ca_path)==0) + { + DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed")); + if (SSL_CTX_set_default_verify_paths(ptr->ssl_context_)==0) + { + DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed")); + report_errors(); + goto ctor_failure; + } + } + + /* DH stuff */ + dh=get_dh512(); + SSL_CTX_set_tmp_dh(ptr->ssl_context_,dh); + DH_free(dh); + +/*if (cipher != NULL) + if(!SSL_CTX_set_cipher_list(ctx,cipher)) { + BIO_printf(bio_err,"error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } +*/ + + DBUG_RETURN(ptr); +ctor_failure: + DBUG_PRINT("exit", ("there was an error")); + my_free((gptr)ptr,MYF(0)); + DBUG_RETURN(0); +} + + +/************************ VioSSLAcceptorFd **********************************/ + +struct st_VioSSLAcceptorFd* +new_VioSSLAcceptorFd(const char* key_file, + const char* cert_file, + const char* ca_file, + const char* ca_path) +{ + int verify = (SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT | + SSL_VERIFY_CLIENT_ONCE); + + struct st_VioSSLAcceptorFd* ptr; + DH *dh=NULL; + DBUG_ENTER("new_VioSSLAcceptorFd"); + DBUG_PRINT("enter", + ("key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s", + key_file, cert_file, ca_path, ca_file)); + + ptr=(struct st_VioSSLAcceptorFd*)my_malloc(sizeof(struct st_VioSSLAcceptorFd),MYF(0)); + ptr->ssl_context_=0; + ptr->ssl_method_=0; + /* FIXME: constants! */ + ptr->session_id_context_ = ptr; + + if (!ssl_algorithms_added) + { + DBUG_PRINT("info", ("todo: OpenSSL_add_all_algorithms()")); + ssl_algorithms_added = TRUE; + OpenSSL_add_all_algorithms(); + + } + if (!ssl_error_strings_loaded) + { + DBUG_PRINT("info", ("todo: SSL_load_error_strings()")); + ssl_error_strings_loaded = TRUE; + SSL_load_error_strings(); + } + ptr->ssl_method_ = TLSv1_server_method(); + ptr->ssl_context_ = SSL_CTX_new(ptr->ssl_method_); + if (ptr->ssl_context_==0) + { + DBUG_PRINT("error", ("SSL_CTX_new failed")); + report_errors(); + goto ctor_failure; + } + /* + * SSL_CTX_set_quiet_shutdown(ctx,1); + * + */ + SSL_CTX_sess_set_cache_size(ptr->ssl_context_,128); + + /* DH? + */ + SSL_CTX_set_verify(ptr->ssl_context_, verify, vio_verify_callback); + SSL_CTX_set_session_id_context(ptr->ssl_context_,(const uchar*)&(ptr->session_id_context_),sizeof(ptr->session_id_context_)); + + /* + * SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile)); + */ + if (vio_set_cert_stuff(ptr->ssl_context_, cert_file, key_file) == -1) + { + DBUG_PRINT("error", ("vio_set_cert_stuff failed")); + report_errors(); + goto ctor_failure; + } + if (SSL_CTX_load_verify_locations( ptr->ssl_context_, ca_file, ca_path)==0) + { + DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed")); + if (SSL_CTX_set_default_verify_paths(ptr->ssl_context_)==0) + { + DBUG_PRINT("error", ("SSL_CTX_set_default_verify_paths failed")); + report_errors(); + goto ctor_failure; + } + } + /* DH stuff */ + dh=get_dh512(); + SSL_CTX_set_tmp_dh(ptr->ssl_context_,dh); + DH_free(dh); + +/*if (cipher != NULL) + if(!SSL_CTX_set_cipher_list(ctx,cipher)) { + BIO_printf(bio_err,"error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } +*/ + + DBUG_RETURN(ptr); +ctor_failure: + DBUG_PRINT("exit", ("there was an error")); + my_free((gptr)ptr,MYF(0)); + DBUG_RETURN(0); +} + + +#endif /* HAVE_OPENSSL */ + + + diff --git a/vio/viotest-ssl.c b/vio/viotest-ssl.c new file mode 100644 index 00000000000..02d47a11294 --- /dev/null +++ b/vio/viotest-ssl.c @@ -0,0 +1,140 @@ +#include <global.h> +#ifdef HAVE_OPENSSL +#include <my_sys.h> +#include <m_string.h> +#include <m_ctype.h> +#include "mysql.h" +#include "errmsg.h" +#include <my_dir.h> +#ifndef __GNU_LIBRARY__ +#define __GNU_LIBRARY__ // Skip warnings in getopt.h +#endif +#include <getopt.h> +//#include "my_readline.h" +#include <signal.h> +#include <violite.h> + +const char *VER="0.1"; + + +#ifndef DBUG_OFF +const char *default_dbug_option="d:t:O,/tmp/viotest-ssl.trace"; +#endif + +void +fatal_error( const char* r) +{ + perror(r); + exit(0); +} + +void +print_usage() +{ + printf("viossl-test: testing SSL virtual IO. Usage:\n"); + printf("viossl-test server-key server-cert client-key client-cert [CAfile] [CApath]\n"); +} + +int +main( int argc, + char** argv) +{ + char* server_key = 0; + char* server_cert = 0; + char* client_key = 0; + char* client_cert = 0; + char* ca_file = 0; + char* ca_path = 0; + int child_pid,sv[2]; + struct st_VioSSLAcceptorFd* ssl_acceptor=0; + struct st_VioSSLConnectorFd* ssl_connector=0; + Vio* client_vio=0; + Vio* server_vio=0; + MY_INIT(argv[0]); +// DBUG_ENTER("main"); + DBUG_PROCESS(argv[0]); + DBUG_PUSH(default_dbug_option); + + + + if (argc<5) + { + print_usage(); + return 1; + } + + server_key = argv[1]; + server_cert = argv[2]; + client_key = argv[3]; + client_cert = argv[4]; + if (argc>5) + ca_file = argv[5]; + if (argc>6) + ca_path = argv[6]; + printf("Server key/cert : %s/%s\n", server_key, server_cert); + printf("Client key/cert : %s/%s\n", client_key, client_cert); + if (ca_file!=0) + printf("CAfile : %s\n", ca_file); + if (ca_path!=0) + printf("CApath : %s\n", ca_path); + + + if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1) + fatal_error("socketpair"); + + ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); + ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path); + + client_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); + client_vio->sd = sv[0]; + sslconnect(ssl_connector,client_vio); + server_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); + server_vio->sd = sv[1]; + sslaccept(ssl_acceptor,server_vio); + + printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); + + child_pid = fork(); + if (child_pid==-1) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("fork"); + } + if (child_pid==0) { + //child, therefore, client + char xbuf[100]; + int r = vio_ssl_read(client_vio,xbuf, sizeof(xbuf)); + if (r<=0) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("client:SSL_read"); + } +// printf("*** client cipher %s\n",client_vio->cipher_description()); + xbuf[r] = 0; + printf("client:got %s\n", xbuf); + my_free((gptr)client_vio,MYF(0)); + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + sleep(1); + } else { + const char* s = "Huhuhuh"; + int r = vio_ssl_write(server_vio,(gptr)s, strlen(s)); + if (r<=0) { + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + fatal_error("server:SSL_write"); + } +// printf("*** server cipher %s\n",server_vio->cipher_description()); + my_free((gptr)server_vio,MYF(0)); + my_free((gptr)ssl_acceptor,MYF(0)); + my_free((gptr)ssl_connector,MYF(0)); + sleep(1); + } + return 0; +} +#else /* HAVE_OPENSSL */ + +int main() { +return 0; +} +#endif /* HAVE_OPENSSL */ diff --git a/vio/viotest-ssl.cc b/vio/viotest-ssl.cc deleted file mode 100644 index a3ad92a7c9c..00000000000 --- a/vio/viotest-ssl.cc +++ /dev/null @@ -1,104 +0,0 @@ -#include "all.h" - -#include <sys/types.h> -#include <sys/socket.h> -#include <stdio.h> -#include <unistd.h> - - -void -fatal_error( const char* r) -{ - perror(r); - exit(0); -} - -void -print_usage() -{ - printf("viossltest: testing SSL virtual IO. Usage:\n"); - printf("viossltest server-key server-cert client-key client-cert [CAfile] [CApath]\n"); -} - -int -main( int argc, - char** argv) -{ - char* server_key = 0; - char* server_cert = 0; - char* client_key = 0; - char* client_cert = 0; - char* ca_file = 0; - char* ca_path = 0; - int sv[2]; - - if (argc<5) - { - print_usage(); - return 1; - } - - if (socketpair(PF_UNIX, SOCK_STREAM, IPPROTO_IP, sv)==-1) - fatal_error("socketpair"); - - server_key = argv[1]; - server_cert = argv[2]; - client_key = argv[3]; - client_cert = argv[4]; - if (argc>5) - ca_file = argv[5]; - if (argc>6) - ca_path = argv[6]; - printf("Server key/cert : %s/%s\n", server_key, server_cert); - printf("Client key/cert : %s/%s\n", client_key, client_cert); - if (ca_file!=0) - printf("CAfile : %s\n", ca_file); - if (ca_path!=0) - printf("CApath : %s\n", ca_path); - - VIO_NS::VioSSLAcceptorFd* ssl_acceptor = new VIO_NS::VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); - VIO_NS::VioSSLConnectorFd* ssl_connector = new VIO_NS::VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path); - - printf("Socketpair: %d , %d\n", sv[0], sv[1]); - - VIO_NS::VioSSL* client_vio = ssl_connector->connect(sv[0]); - VIO_NS::VioSSL* server_vio = ssl_acceptor->accept(sv[1]); - - - int child_pid = fork(); - if (child_pid==-1) { - delete ssl_acceptor; - delete ssl_connector; - fatal_error("fork"); - } - if (child_pid==0) { - //child, therefore, client - char xbuf[100]; - int r = client_vio->read(xbuf, sizeof(xbuf)); - if (r<=0) { - delete ssl_acceptor; - delete ssl_connector; - fatal_error("client:SSL_read"); - } - printf("*** client cipher %s\n",client_vio->cipher_description()); - xbuf[r] = 0; - printf("client:got %s\n", xbuf); - delete client_vio; - delete ssl_acceptor; - delete ssl_connector; - sleep(1); - } else { - const char* s = "Huhuhuh"; - int r = server_vio->write((void *)s, strlen(s)); - if (r<=0) { - delete ssl_acceptor; - delete ssl_connector; - fatal_error("server:SSL_write"); - } - printf("*** server cipher %s\n",server_vio->cipher_description()); - delete server_vio; - delete ssl_acceptor; - delete ssl_connector; - sleep(1); - } -} diff --git a/vio/viotypes.h b/vio/viotypes.h deleted file mode 100644 index 8d36a35c86f..00000000000 --- a/vio/viotypes.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -** Virtual I/O library -** Written by Andrei Errapart <andreie@no.spam.ee> -*/ - -/* - * Some typedefs to external types. - */ -#ifndef vio_viotypes_h_ -#define vio_viotypes_h_ - -#include <stdarg.h> -#include <stdio.h> -#include <sys/types.h> - -typedef int vio_bool_t; -typedef void* vio_ptr_t; - -#ifdef __cplusplus -VIO_NS_BEGIN - -typedef vio_ptr_t vio_ptr; -typedef char* vio_cstring; -typedef int32_t vio_int32; -typedef u_int32_t vio_uint32; -typedef vio_bool_t vio_bool; - -VIO_NS_END -#endif /* __cplusplus */ - -#endif /* vio_types_h_ */ - |