diff options
author | David Shaw <[email protected]> | 2002-06-29 13:46:34 +0000 |
---|---|---|
committer | David Shaw <[email protected]> | 2002-06-29 13:46:34 +0000 |
commit | 3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37 (patch) | |
tree | dac7a3780fb4edf9ca89c93800230e88ab255434 /util | |
parent | Update head to match stable 1.0 (diff) | |
download | gnupg-3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37.tar.gz gnupg-3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37.zip |
Update head to match stable 1.0
Diffstat (limited to 'util')
-rw-r--r-- | util/ChangeLog | 513 | ||||
-rw-r--r-- | util/Makefile.am | 31 | ||||
-rw-r--r-- | util/README | 7 | ||||
-rw-r--r-- | util/argparse.c | 1000 | ||||
-rw-r--r-- | util/dotlock.c | 420 | ||||
-rw-r--r-- | util/errors.c | 20 | ||||
-rw-r--r-- | util/fileutil.c | 103 | ||||
-rw-r--r-- | util/g10u.c | 40 | ||||
-rw-r--r-- | util/http.c | 231 | ||||
-rw-r--r-- | util/iobuf.c | 947 | ||||
-rw-r--r-- | util/logger.c | 103 | ||||
-rw-r--r-- | util/memory.c | 634 | ||||
-rw-r--r-- | util/miscutil.c | 116 | ||||
-rw-r--r-- | util/riscos.c | 327 | ||||
-rw-r--r-- | util/secmem.c | 468 | ||||
-rw-r--r-- | util/simple-gettext.c | 10 | ||||
-rw-r--r-- | util/strgutil.c | 606 | ||||
-rw-r--r-- | util/ttyio.c | 128 | ||||
-rw-r--r-- | util/w32reg.c | 74 |
19 files changed, 5171 insertions, 607 deletions
diff --git a/util/ChangeLog b/util/ChangeLog index 20e9bda3e..c01b5e207 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,129 +1,464 @@ -Mon Sep 18 16:35:45 CEST 2000 Werner Koch <[email protected]> +2002-06-21 Stefan Bellon <[email protected]> - * strgutil.c (utf8_to_native): Fixed null ptr problem. By - Giampaolo Tomassoni. + * riscos.c (riscos_global_defaults): New. + +2002-06-20 Stefan Bellon <[email protected]> + + * riscos.c (riscos_set_filetype_by_number, riscos_set_filetype): + New. Set RISC OS filetype according to MIME type. + +2002-06-14 David Shaw <[email protected]> + + * strgutil.c (pop_strlist): New function to pop the head off of a + strlist. + +2002-06-05 Timo Schulz <[email protected]> + + * fileutil.c (is_file_compressed): Corrected the magic values + for bzip2 and gzip. Noted by David. + +2002-05-22 Werner Koch <[email protected]> + + * fileutil.c (compare_filenames): Replaced stricmp by strcasecmp. + * miscutil.c (answer_is_yes_no_quit,answer_is_yes_no_default): Ditto. + + * strgutil.c (strncasecmp): New. + (memicmp): Removed. + +2002-05-10 Stefan Bellon <[email protected]> + + * memory.c (add_entry) [M_DEBUG]: Added some missing EXTRA_ALIGN. + (free_entry) [M_DEBUG]: Free secure memory via secmem_free. + (alloc_secure): Malloc at least 1 byte. + (realloc) [M_GUARD]: Added missing FNAMEARG to function call. + + * logger.c (g10_log_bug0) [__riscos__]: Make use of first + g10_log_bug0 function for later Norcroft compiler. + + * riscos.c: Added stdlib.h include. + +2002-05-04 Werner Koch <[email protected]> + + * http.c (write_server) [__MINGW32__]: Replaced WriteFile by send + because sockets don't work with WriteFile under NT anymore. + +2002-05-03 David Shaw <[email protected]> + + * argparse.c (optfile_parse): Remove quotes only if they totally + enclose the string, and do not occur within the string. This + makes specifying a program under Win32 easier when you need quotes + around part of a string, but not around the whole string. + +2002-05-02 Werner Koch <[email protected]> + + * memory.c (alloc): Malloc at least 1 byte. Noted by Winona Brown. + +2002-04-23 David Shaw <[email protected]> + + * miscutil.c: New function answer_is_yes_no_default() to give a + default answer. + +2002-04-22 Stefan Bellon <[email protected]> + + * riscos.c (riscos_open, riscos_fopen, riscos_fstat, set_filetype): + Removed as they're not needed anymore. + + * iobuf.c (direct_open) [__riscos__]: Don't allow opening of + directories. + +2002-04-08 Werner Koch <[email protected]> + + Fixed filename of last entry. + +2002-03-29 David Shaw <[email protected]> + + * miscutil.c (print_string, utf8_to_native): If a delimiter is + used, then quote the backslash character as well. Problem noted + by Rainer Perske. + +2002-03-15 Werner Koch <[email protected]> + + * argparse.c (optfile_parse): Fixed missing argument handling. + +2002-02-28 Timo Schulz <[email protected]> + + * http.c (write_server): Convert integer to a HANDLE for W32. + +2002-01-27 David Shaw <[email protected]> + + * iobuf.c (iobuf_fdopen, iobuf_sockopen): Do not cache fdopened + fds on close. + +2002-01-08 Werner Koch <[email protected]> + + * secmem.c (print_warn): Print a pointer to the FAQ. + +2002-01-05 Werner Koch <[email protected]> + + * argparse.c (default_strusage): Set default copyright date to 2002. + +2002-01-02 Stefan Bellon <[email protected]> + + * iobuf.c [__riscos__]: Updated include file name. + + * fileutil.c [__riscos__]: Ditto. + + * ttyio.d [__riscos__]: Ditto. + + * riscos.c [__riscos__]: Ditto. Added debugging code and + unified error messages. + +2001-12-27 David Shaw <[email protected]> + + * errors.c (g10_errstr): Added G10ERR_KEYSERVER + +2001-12-27 Werner Koch <[email protected]> + + * simple-gettext.c [MINGW32]: Fixed last changed. + +2001-12-22 Stefan Bellon <[email protected]> + + * memory.c (realloc): Fixed realloc not working when M_GUARD is + defined and first parameter is NULL. + +2001-12-22 Timo Schulz <[email protected]> + + * fileutil.c (is_file_compressed): New. + +2001-12-19 Werner Koch <[email protected]> + + * simple-gettext.c, w32reg.c [CYGWIN32]: Allow to use this file + +2001-10-11 Werner Koch <[email protected]> + + * http.c (do_parse_uri): Changed initialization of the port number + so that it does also work with x-hkp. By David Shaw. + +2001-09-19 Werner Koch <[email protected]> + + * w32reg.c (get_root_key): New. + (read_w32_registry_string): Use it here. + (write_w32_registry_string): New. Contributed by Timo. + + * iobuf.c (iobuf_ioctl): New command to disable fd + caching. Implemented no_cache flag where needed. + (iobuf_sockopen): Always set no_cache flag. + + * strgutil.c (utf8_to_native): Add a delim arg and changed all + callers. Make sure that quoting is done when translation is + disabled. + * miscutil.c (print_utf8_string2): New. + +2001-09-17 Werner Koch <[email protected]> + + * miscutil.c (print_string): Use explicit ranges and not iscntrl(). + (make_printable_string): Ditto. + +2001-09-07 Werner Koch <[email protected]> + + * strgutil.c (strsep): New, taken from glibc 2.2.1. + +2001-09-03 Werner Koch <[email protected]> + + * miscutil.c (strtimestamp,asctimestamp): Avoid trigraphs. + +2001-08-21 Stefan Bellon <[email protected]> + + * riscos.c [__riscos__] (close_fds): Fixed possible endless loop. + +2001-08-20 Werner Koch <[email protected]> + + Applied patches from Stefan Bellon <[email protected]> to support + RISC OS. Nearly all of these patches are identified by the + __riscos__ macro. + * secmem.c [__riscos__]: Disabled secure memory stuff. + * dotlock.c, ttyio.c [__riscos__]: Adapted for RISC OS + * fileutil.c, iobuf.c: Adapted for RISC OS; mainly replaced + hardcoded path separators with EXTSEP_S like macros. + * http.c (send_request): Use macros for the env-var name. + * logger.c [__riscos__]: Do an fflush at the end of each log + function. + * memory.c [__riscos__]: Minor patches + * riscos.c (set_filetype): New. + + * secmem.c (lock_pool): Under HPUX mlock is broken but we might + have plock, so we use this to lock the entire process. By Albert + Chin. + +2001-07-03 Werner Koch <[email protected]> + + * strgutil.c (utf8_to_native): Fixed printing of invalid utf-8 + characters. Thomas Roessler reported that the escaping didn't work + correct. + +2001-06-12 Werner Koch <[email protected]> + + * strgutil.c (ascii_memistr,ascii_isupper,ascii_islower, + ascii_toupper,ascii_tolower, ascii_strcasecmp, ascii_memcasecmp): New. + (set_native_charset): Use ascii_strcasecmp() + * fileutil.c (compare_filenames): Ditto + * miscutil.c (answer_is_yes): Ditto. + (answer_is_yes_no_quit): Ditto. + +2001-06-06 Werner Koch <[email protected]> + + * strgutil.c (vasprintf) [__MINGW32__]: New. Taken from libiberty. + * ttyio.c (tty_printf) [__MINGW32__]: Replaced the sprintf with + the new vasprintf. + +2001-06-05 Werner Koch <[email protected]> + + * dotlock.c (make_dotlock): Typo fixes. + +2001-05-25 Werner Koch <[email protected]> + + * ttyio.c (do_get): Fixed a serious format string bug. Thanks to + fish stiqz. + +2001-05-23 Werner Koch <[email protected]> + + * secmem.c (EPERM): Try to work around a Slackware problem. + +2001-05-05 Werner Koch <[email protected]> + + * http.c (http_start_data): Flush before writing. + (http_wait_response): No need to flush here. + +2001-04-27 Werner Koch <[email protected]> + + * memory.c (out_of_core): Print an explanation on reasons why + secret memory can get exhausted. + +2001-04-23 Werner Koch <[email protected]> + + * http.c (http_wait_response): Implement new flag to inhibit the + TCP shutdown. + +2001-04-20 Werner Koch <[email protected]> + + * http.c (http_start_data): Use write_server and not the iobuf + stuff. I wonder why we are at all using write_server - shouldn't + it be handled by iobuf? + + * strgutil.c (set_native_charset): Allow utf-8 by introducing the + new no_translation variable. + (native_to_utf8): Handle no_translation. + (utf8_to_native): Ditto. + +2001-04-19 Werner Koch <[email protected]> + + * miscutil.c (asctimestamp): Handle negative times. We must do + this because Windoze segvs on negative times passed to gmtime(). + (strtimestamp): Ditto. + +2001-04-14 Werner Koch <[email protected]> + + * strgutil.c (utf8_to_native): Fixed a segv. Thanks to Keith Clayton. + +2001-04-13 Werner Koch <[email protected]> + + * iobuf.c (iobuf_fopen): Removed because it is not used and + furthermore mode is ignored for an fname of "-". Suggested by + Florian Weimer. + +2001-04-02 Werner Koch <[email protected]> + + * iobuf.c (translate_file_handle): New. Use this function + everywhere in this file. + (iobuf_translate_file_handle): Always use the osfhandle stuff here + because callers don't know the implementation details of iobuf and + they expect that the handles are translated. + +2001-03-29 Werner Koch <[email protected]> + + * miscutil.c (answer_is_yes): An empty string does now return no. + (answer_is_yes_no_quit): Likewise. + + * iobuf.c (iobuf_close): Burn the buffers. + +2001-03-26 Werner Koch <[email protected]> + + * ttyio.c: Define TERMDEVICE depending on OS. + + * http.c (http_start_data): send a CRLF and not just a LF. + Pointed out by Steven Murdoch. + +2001-03-13 Werner Koch <[email protected]> + + * iobuf.c (iobuf_sockopen): New. + (sock_filter) [__MINGW32__]: New. + (iobuf_ioctl): New. + (file_filter): Implemented keep_open mode. + * http.c (http_open, http_wait_response): Replaced iobuf_fdopen by + iobuf_sockopen and use an iobuf_ioctl to avoid the dup(). + (deinit_sockets, init_sockets) [__MINGW32__]: New. + (connect_server, write_server): Add code to work with W32 sockets. + +2001-03-12 Werner Koch <[email protected]> + + * strgutil.c (check_trailing_chars,check_trailing_ws): New. + +2001-03-08 Werner Koch <[email protected]> + + * argparse.c (default_strusage): Changed year of printed copyright + to 2001. + + * iobuf.c (fd_cache_invalidate, fd_cache_close, fd_cache_open): New. + (direct_open): Invalidate the fd_cache for read access. + (file_filter): Cache the close here. + (iobuf_open): Use new my_fopen_ro macro to try the cache first. + +2001-03-07 Werner Koch <[email protected]> + + * iobuf.c: Made the old stdio file handling cpp conditional + controlled by FILE_FILTER_USES_STDIO and added a new + open/read/close based one. We don't need the stdio buffering + becuase we are doing our own buffering anyway. And it is a + prerequesite to allow the use of ReadFile et al for W32 which in + turn is needed to make the http stuff work there. The new W32 + stuff has also been implemented. Minor changes to all open functions. + (direct_open): New. + (file_filter): Core of the new read/write handling. + (iobuf_get_filelength): Use W32 API function here. But it is + currently limited to 2GB files. + (iobuf_seek): Ditto. + +2001-03-01 Werner Koch <[email protected]> + + * errors.c (g10_errstr): New codes UNU_SECKEY and UNU_PUBKEY. + +2000-12-28 Werner Koch <[email protected]> + + * dotlock.c: Made all_lockfiles volatile. + (remove_lockfiles): Made public. + +2000-11-30 Werner Koch <[email protected]> + + * iobuf.c (iobuf_translate_file_handle): New. + (iobuf_open, iobuf_create): Use it for special filenames + +2000-11-11 Paul Eggert <[email protected]> + + * iobuf.c (iobuf_get_filelength): Now returns off_t, not u32. + Remove kludges to worry about large files; the callers check + for files that are too large, and they should already be doing + the right thing in an implementation-independent way. + (fopen, fstat): Remove macros. + + * iobuf.c (iobuf_set_limit, iobuf_tell, iobuf_seek): + Use off_t, not ulong, for file offsets. + (<limits.h>): Include if needed. + (LONG_MAX, LONG_MIN): Define a substitute if needed. + (fseeko): Define a substitute if needed. + + * iobuf.c (iobuf_seek): Do not use %lu to report file + +2000-11-09 Werner Koch <[email protected]> + + * iobuf.c (iobuf_enable_special_filenames): New. + (check_special_filename): New. + (iobuf_open): check for special filenames. + (iobuf_create): Ditto. + +2000-10-23 Werner Koch <[email protected]> + + * secmem.c (lock_pool): Don't print warning for Windows. + +2000-10-16 Werner Koch <[email protected]> + + * secmem.c (lock_pool): Fixed error checking for Linux. + By James Troup. + +Thu Sep 14 14:20:38 CEST 2000 Werner Koch <[email protected]> + + * miscutil.c (answer_is_yes_no_quit): Swapped order of yes/no test + so that no is returned for an empty input. By David Champion. + +Wed Sep 6 17:55:47 CEST 2000 Werner Koch <[email protected]> * iobuf.c: Use fopen64 insead of fopen when available. (iobuf_get_filelength): Use fstat64 when available but return 2^32-1 if the file is larger than this value. - * miscutil.c (answer_is_yes_no_quit): Swapped order of yes/no test - so that no is returned for an empty input. By David Champion. +Wed Sep 6 14:59:09 CEST 2000 Werner Koch <[email protected]> -Fri Aug 18 14:27:14 CEST 2000 Werner Koch <[email protected]> + * secmem.c (secmem_realloc): check for failed secmem_malloc. By + Matt Kraai. - * logger.c (log_set_file): Allow to set the file by name. + * strgutil.c (utf8_to_native): Fixed null ptr problem. By + Giampaolo Tomassoni. -Fri Jul 28 18:19:11 CEST 2000 Werner Koch <[email protected]> +Thu Jul 27 10:02:38 CEST 2000 Werner Koch <[email protected]> * iobuf.c: Use setmode() at several places to set stdin and stdout to binary mode for MSDOS based systems * iobuf.c (underflow): Initialize dummy_len to keep memory checker happy. -Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@> - - * iobuf.c (iobuf_cancel): Broadcast the new Cancel message to all - filters. Fix for MSDOS. - - * miscutil.c (asctimestamp): Fix for possible buffer overflow by - a large system returned date format string. - - * logger.c (log_inc_errorcount): New. +Fri Jun 9 10:09:52 CEST 2000 Werner Koch <[email protected]> - * w32reg.c: New. + * ttyio.c: Simulate termios with termios. By Dave Dykstra. - * simple-gettext.c: Use the Registry to locate the mo file. +Thu Jun 8 20:22:00 CEST 2000 Werner Koch <[email protected]> - * http.c (send_request): Add support for proxys; suggested by - Walter Hofmann. - (http_open_document): Pass flags to http_open. + * secmem.c (lock_pool,secmem_init): Additional check for dropped privs. - * ttyio.c (do_get): Replaced #if __MINGW32__ by #ifdef because - gcc 2.95.1 assigns a floating point value (0.2) to this macro, - which in turn can't be used in an expression. - * ttyio.c: Simulate termios with termios. By Dave Dykstra. - * ttyio.c (tty_print_utf8_string): Oops. - * ttyio.c (tty_print_utf8_string2): New to allow a max output size. +Tue May 30 16:37:55 CEST 2000 Werner Koch <[email protected]> -Thu Jan 27 18:00:44 CET 2000 Werner Koch <[email protected]> + * iobuf.c (iobuf_cancel): Fix for MSDOS. - * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_". +Fri Apr 14 19:37:08 CEST 2000 Werner Koch <[email protected]> -Mon Jan 24 13:04:28 CET 2000 Werner Koch <[email protected]> + * dotlock.c (disable_dotlock): New. Implmented this in the module. - * memory.c: Removed - * secmem.c: Moved to ../gcrypt. - * argparse.c argparse.h logging.c logging.h - mischelp.h stringhelp.c stringhelp.h xmalloc.c - xmalloc.h dotlock.c: Moved to ../jnlib - * libutil-config.h: Removed. +2000-03-09 14:04:22 Werner Koch ([email protected]) - * logging.c (log_set_file): New. - (log_printf): New. - (do_logv): Add kludge to insert LFs. + * argparse.c (default_strusage): Changed year of default copyright. - * Replaced all m_ memory fucntions by gcry_ ones. - * README: New. +Tue Mar 7 18:45:31 CET 2000 Werner Koch <[email protected]> -Fri Dec 31 12:48:31 CET 1999 Werner Koch <[email protected]> + * secmem.c (lock_pool): No more warning for QNX. By Sam Roberts. - * memory.c (m_is_secure): New. +2000-03-02 15:51:04 Werner Koch ([email protected]) - * stringhelp.c (trim_trailing_spaces): New. + * ttyio.c (tty_print_utf8_string): Oops. -Wed Dec 8 21:58:32 CET 1999 Werner Koch <[email protected]> +Thu Mar 2 15:37:46 CET 2000 Werner Koch <[email protected]> - * strgutil.c (strcasecmp): New. + * ttyio.c (tty_print_utf8_string2): New to allow a max output size. - * argparse.h: New. - * libutil.h: New. - * argparse.c: Use these new files. - (optfile_parse): s/m_alloc/libutil_xalloc/ +Wed Feb 23 10:07:57 CET 2000 Werner Koch <[email protected]> - * strgutil.c: Moved a lot of function to ... - * stringhelp.c: ... this new file - * stringhelp.h: ... and the definitions to here + * miscutil.c (asctimestamp): Fix for possible buffer overflow by + large system returned date format string. - * mischelp.h: New. +Fri Dec 31 14:08:15 CET 1999 Werner Koch <[email protected]> - * logging.h: New, but not yet used in GnuPG. - * logging.c: Ditto. + * logger.c (log_inc_errorcount): New. -Fri Nov 19 17:15:20 CET 1999 Werner Koch <[email protected]> +Sat Dec 4 12:30:28 CET 1999 Werner Koch <[email protected]> - * argparse.c (default_strusage): Renamed to strusage. Fall back - to the old behaviour if no sepcial strhandler has been set. + * iobuf.c (iobuf_cancel): Broadcast the new Cancel mesaage to all + filters. - * memory.c (g10_private_check_heap): New. +Mon Nov 22 11:14:53 CET 1999 Werner Koch <[email protected]> - * secmem.c (m_is_secure): Renamed to ... - (g10_private_is_secure): ... this. - * memory.c (g10_private_malloc): New. Takes core functionalty of ... - (m_alloc): ... and calls it. - (g10_private_malloc_secure): New. Takes core functionalty of ... - (m_alloc_secure): ... and calls it. - (g10_private_realloc): New. Takes core functionalty of ... - (m_realloc): ... and this one calls it. - (g10_private_free): Wraps around m_free(). + * strgutil.c (strcasecmp): New. - * argparse.c (g10_set_strusage): New. - (default_strusage): renamed to ... - (g10_default_strusage): .. this. + * secmem.c (pool_is_mmapped): Made volatile. -Sat Nov 13 17:44:23 CET 1999 Werner Koch <[email protected]> +Sat Oct 9 20:34:41 CEST 1999 Werner Koch <[email protected]> - * g10u.c: Removed. + * Makefile.am: Removed libtool. - * errors.c (g10_errstr): Use gcry_strerror as fallback +Fri Oct 8 20:32:01 CEST 1999 Werner Koch <[email protected]> -Tue Oct 26 14:10:21 CEST 1999 Werner Koch <[email protected]> + * w32reg.c: New. + * simple-gettext.c: Use the Registry to locate the mo file. - * simple-gettext.c (set_gettext_file): Check charset and do - mapping only for IBM850. - * strgutil.c (query_native_charset): New. - (get_native_charset): Try to get it from the system on the first call. - (ibm850_unicode): New table. + * http.c (send_request): Add support for proxys; suggested by + Walter Hofmann. + (http_open_document): Pass flags to http_open. Fri Sep 17 12:56:42 CEST 1999 Werner Koch <[email protected]> @@ -208,7 +543,7 @@ Sat Jun 26 12:15:59 CEST 1999 Werner Koch <[email protected]> Fri Jun 18 00:18:02 CEST 1999 Michael Roth <[email protected]> * iobuf.c: file_filter() Detection of EOF on terminals - improved/fixed (see Bug #21). + improved/fixed (see Bug #21). Mon Jun 14 21:18:54 CEST 1999 Michael Roth <[email protected]> @@ -581,3 +916,15 @@ Fri Feb 13 15:14:13 1998 Werner Koch ([email protected]) * argparse.c (show_help): New '\v' kludge. + + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/util/Makefile.am b/util/Makefile.am index 28d0c8cb3..a8d40da2d 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,13 +1,32 @@ +# Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +# +# This file is part of GnuPG. +# +# GnuPG 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. +# +# GnuPG 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 + ## Process this file with automake to produce Makefile.in -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -EXTRA_DIST = README +INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl noinst_LIBRARIES = libutil.a -libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \ - ttyio.c errors.c iobuf.c \ - http.c simple-gettext.c w32reg.c + +#libutil_a_LDFLAGS = +libutil_a_SOURCES = g10u.c logger.c fileutil.c miscutil.c strgutil.c \ + ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \ + dotlock.c http.c simple-gettext.c w32reg.c http-test: http.c @@ -16,5 +35,3 @@ http-test: http.c - - diff --git a/util/README b/util/README deleted file mode 100644 index 168c58a7c..000000000 --- a/util/README +++ /dev/null @@ -1,7 +0,0 @@ -Here you find supporting code for GnuPG and the tools. It needs some -support from libgcrypt. - -util is not a good name, so at some time we should rename the whole source -tree. However this is not easy for CVS and diff reasons. - - diff --git a/util/argparse.c b/util/argparse.c new file mode 100644 index 000000000..c3cc3d709 --- /dev/null +++ b/util/argparse.c @@ -0,0 +1,1000 @@ +/* [argparse.c wk 17.06.97] Argument Parser for option handling + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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: This is an independent version of the one in WkLib + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#include "util.h" +#include "i18n.h" + + +/********************************* + * @Summary arg_parse + * #include <wk/lib.h> + * + * typedef struct { + * char *argc; pointer to argc (value subject to change) + * char ***argv; pointer to argv (value subject to change) + * unsigned flags; Global flags (DO NOT CHANGE) + * int err; print error about last option + * 1 = warning, 2 = abort + * int r_opt; return option + * int r_type; type of return value (0 = no argument found) + * union { + * int ret_int; + * long ret_long + * ulong ret_ulong; + * char *ret_str; + * } r; Return values + * struct { + * int idx; + * const char *last; + * void *aliases; + * } internal; DO NOT CHANGE + * } ARGPARSE_ARGS; + * + * typedef struct { + * int short_opt; + * const char *long_opt; + * unsigned flags; + * } ARGPARSE_OPTS; + * + * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); + * + * @Description + * This is my replacement for getopt(). See the example for a typical usage. + * Global flags are: + * Bit 0 : Do not remove options form argv + * Bit 1 : Do not stop at last option but return other args + * with r_opt set to -1. + * Bit 2 : Assume options and real args are mixed. + * Bit 3 : Do not use -- to stop option processing. + * Bit 4 : Do not skip the first arg. + * Bit 5 : allow usage of long option with only one dash + * Bit 6 : ignore --version and --help + * all other bits must be set to zero, this value is modified by the + * function, so assume this is write only. + * Local flags (for each option): + * Bit 2-0 : 0 = does not take an argument + * 1 = takes int argument + * 2 = takes string argument + * 3 = takes long argument + * 4 = takes ulong argument + * Bit 3 : argument is optional (r_type will the be set to 0) + * Bit 4 : allow 0x etc. prefixed values. + * Bit 7 : this is a command and not an option + * You stop the option processing by setting opts to NULL, the function will + * then return 0. + * @Return Value + * Returns the args.r_opt or 0 if ready + * r_opt may be -2/-7 to indicate an unknown option/command. + * @See Also + * ArgExpand + * @Notes + * You do not need to process the options 'h', '--help' or '--version' + * because this function includes standard help processing; but if you + * specify '-h', '--help' or '--version' you have to do it yourself. + * The option '--' stops argument processing; if bit 1 is set the function + * continues to return normal arguments. + * To process float args or unsigned args you must use a string args and do + * the conversion yourself. + * @Example + * + * ARGPARSE_OPTS opts[] = { + * { 'v', "verbose", 0 }, + * { 'd', "debug", 0 }, + * { 'o', "output", 2 }, + * { 'c', "cross-ref", 2|8 }, + * { 'm', "my-option", 1|8 }, + * { 500, "have-no-short-option-for-this-long-option", 0 }, + * {0} }; + * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } + * + * while( ArgParse( &pargs, &opts) ) { + * switch( pargs.r_opt ) { + * case 'v': opt.verbose++; break; + * case 'd': opt.debug++; break; + * case 'o': opt.outfile = pargs.r.ret_str; break; + * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + * case 500: opt.a_long_one++; break + * default : pargs.err = 1; break; -- force warning output -- + * } + * } + * if( argc > 1 ) + * log_fatal( "Too many args"); + * + */ + +typedef struct alias_def_s *ALIAS_DEF; +struct alias_def_s { + ALIAS_DEF next; + char *name; /* malloced buffer with name, \0, value */ + const char *value; /* ptr into name */ +}; + +static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); +static void show_help(ARGPARSE_OPTS *opts, unsigned flags); +static void show_version(void); + +static void +initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno ) +{ + if( !(arg->flags & (1<<15)) ) { /* initialize this instance */ + arg->internal.idx = 0; + arg->internal.last = NULL; + arg->internal.inarg = 0; + arg->internal.stopped = 0; + arg->internal.aliases = NULL; + arg->internal.cur_alias = NULL; + arg->err = 0; + arg->flags |= 1<<15; /* mark initialized */ + if( *arg->argc < 0 ) + log_bug("Invalid argument for ArgParse\n"); + } + + + if( arg->err ) { /* last option was erroneous */ + const char *s; + + if( filename ) { + if( arg->r_opt == -6 ) + s = "%s:%u: argument not expected\n"; + else if( arg->r_opt == -5 ) + s = "%s:%u: read error\n"; + else if( arg->r_opt == -4 ) + s = "%s:%u: keyword too long\n"; + else if( arg->r_opt == -3 ) + s = "%s:%u: missing argument\n"; + else if( arg->r_opt == -7 ) + s = "%s:%u: invalid command\n"; + else if( arg->r_opt == -10 ) + s = "%s:%u: invalid alias definition\n"; + else + s = "%s:%u: invalid option\n"; + log_error(s, filename, *lineno ); + } + else { + if( arg->r_opt == -3 ) + s = "Missing argument for option \"%.50s\"\n"; + else if( arg->r_opt == -6 ) + s = "Option \"%.50s\" does not expect an argument\n"; + else if( arg->r_opt == -7 ) + s = "Invalid command \"%.50s\"\n"; + else if( arg->r_opt == -8 ) + s = "Option \"%.50s\" is ambiguous\n"; + else if( arg->r_opt == -9 ) + s = "Command \"%.50s\" is ambiguous\n"; + else + s = "Invalid option \"%.50s\"\n"; + log_error(s, arg->internal.last? arg->internal.last:"[??]" ); + } + if( arg->err != 1 ) + exit(2); + arg->err = 0; + } + + /* clearout the return value union */ + arg->r.ret_str = NULL; + arg->r.ret_long= 0; +} + + +static void +store_alias( ARGPARSE_ARGS *arg, char *name, char *value ) +{ + /* TODO: replace this dummy function with a rea one + * and fix the probelms IRIX has with (ALIAS_DEV)arg.. + * used as lvalue + */ +#if 0 + ALIAS_DEF a = m_alloc( sizeof *a ); + a->name = name; + a->value = value; + a->next = (ALIAS_DEF)arg->internal.aliases; + (ALIAS_DEF)arg->internal.aliases = a; +#endif +} + +/**************** + * Get options from a file. + * Lines starting with '#' are comment lines. + * Syntax is simply a keyword and the argument. + * Valid keywords are all keywords from the long_opt list without + * the leading dashes. The special keywords "help", "warranty" and "version" + * are not valid here. + * The special keyword "alias" may be used to store alias definitions, + * which are later expanded like long options. + * Caller must free returned strings. + * If called with FP set to NULL command line args are parse instead. + * + * Q: Should we allow the syntax + * keyword = value + * and accept for boolean options a value of 1/0, yes/no or true/false? + * Note: Abbreviation of options is here not allowed. + */ +int +optfile_parse( FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int state, i, c; + int idx=0; + char keyword[100]; + char *buffer = NULL; + size_t buflen = 0; + int inverse=0; + int in_alias=0; + + if( !fp ) /* same as arg_parse() in this case */ + return arg_parse( arg, opts ); + + initialize( arg, filename, lineno ); + + /* find the next keyword */ + state = i = 0; + for(;;) { + c=getc(fp); + if( c == '\n' || c== EOF ) { + if( c != EOF ) + ++*lineno; + if( state == -1 ) + break; + else if( state == 2 ) { + keyword[i] = 0; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if( inverse ) /* this does not have an effect, hmmm */ + arg->r_opt = -arg->r_opt; + if( !opts[idx].short_opt ) /* unknown command/option */ + arg->r_opt = (opts[idx].flags & 256)? -7:-2; + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ + arg->r_type = 0; /* okay */ + else if( (opts[idx].flags & 8) ) /* argument is optional */ + arg->r_type = 0; /* okay */ + else /* required argument */ + arg->r_opt = -3; /* error */ + break; + } + else if( state == 3 ) { /* no argument found */ + if( in_alias ) + arg->r_opt = -3; /* error */ + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ + arg->r_type = 0; /* okay */ + else if( (opts[idx].flags & 8) ) /* no optional argument */ + arg->r_type = 0; /* okay */ + else /* no required argument */ + arg->r_opt = -3; /* error */ + break; + } + else if( state == 4 ) { /* have an argument */ + if( in_alias ) { + if( !buffer ) + arg->r_opt = -6; + else { + char *p; + + buffer[i] = 0; + p = strpbrk( buffer, " \t" ); + if( p ) { + *p++ = 0; + trim_spaces( p ); + } + if( !p || !*p ) { + m_free( buffer ); + arg->r_opt = -10; + } + else { + store_alias( arg, buffer, p ); + } + } + } + else if( !(opts[idx].flags & 7) ) /* does not take an arg */ + arg->r_opt = -6; /* error */ + else { + char *p; + if( !buffer ) { + keyword[i] = 0; + buffer = m_strdup(keyword); + } + else + buffer[i] = 0; + + trim_spaces( buffer ); + p = buffer; + /* remove quotes if they totally enclose the + string, and do not occur within the string */ + if( *p == '"' && p[strlen(p)-1]=='"') { + char *i=p; + + while(*(++i)) + if(*i=='"') + break; + + if(*i=='"' && *(i+1)=='\0') { + p[strlen(p)-1] = 0; + p++; + } + } + if( !set_opt_arg(arg, opts[idx].flags, p) ) + m_free(buffer); + } + break; + } + else if( c == EOF ) { + if( ferror(fp) ) + arg->r_opt = -5; /* read error */ + else + arg->r_opt = 0; /* eof */ + break; + } + state = 0; + i = 0; + } + else if( state == -1 ) + ; /* skip */ + else if( !state && isspace(c) ) + ; /* skip leading white space */ + else if( !state && c == '#' ) + state = 1; /* start of a comment */ + else if( state == 1 ) + ; /* skip comments */ + else if( state == 2 && isspace(c) ) { + keyword[i] = 0; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if( !opts[idx].short_opt ) { + if( !strcmp( keyword, "alias" ) ) { + in_alias = 1; + state = 3; + } + else { + arg->r_opt = (opts[idx].flags & 256)? -7:-2; + state = -1; /* skip rest of line and leave */ + } + } + else + state = 3; + } + else if( state == 3 ) { /* skip leading spaces of the argument */ + if( !isspace(c) ) { + i = 0; + keyword[i++] = c; + state = 4; + } + } + else if( state == 4 ) { /* collect the argument */ + if( buffer ) { + if( i < buflen-1 ) + buffer[i++] = c; + else { + buflen += 50; + buffer = m_realloc(buffer, buflen); + buffer[i++] = c; + } + } + else if( i < DIM(keyword)-1 ) + keyword[i++] = c; + else { + buflen = DIM(keyword)+50; + buffer = m_alloc(buflen); + memcpy(buffer, keyword, i); + buffer[i++] = c; + } + } + else if( i >= DIM(keyword)-1 ) { + arg->r_opt = -4; /* keyword to long */ + state = -1; /* skip rest of line and leave */ + } + else { + keyword[i++] = c; + state = 2; + } + } + + return arg->r_opt; +} + + + +static int +find_long_option( ARGPARSE_ARGS *arg, + ARGPARSE_OPTS *opts, const char *keyword ) +{ + int i; + size_t n; + + /* Would be better if we can do a binary search, but it is not + possible to reorder our option table because we would mess + up our help strings - What we can do is: Build a nice option + lookup table wehn this function is first invoked */ + if( !*keyword ) + return -1; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + return i; + #if 0 + { + ALIAS_DEF a; + /* see whether it is an alias */ + for( a = args->internal.aliases; a; a = a->next ) { + if( !strcmp( a->name, keyword) ) { + /* todo: must parse the alias here */ + args->internal.cur_alias = a; + return -3; /* alias available */ + } + } + } + #endif + /* not found, see whether it is an abbreviation */ + /* aliases may not be abbreviated */ + n = strlen( keyword ); + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) { + int j; + for(j=i+1; opts[j].short_opt; j++ ) { + if( opts[j].long_opt + && !strncmp( opts[j].long_opt, keyword, n ) ) + return -2; /* abbreviation is ambiguous */ + } + return i; + } + } + return -1; +} + +int +arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int idx; + int argc; + char **argv; + char *s, *s2; + int i; + + initialize( arg, NULL, NULL ); + argc = *arg->argc; + argv = *arg->argv; + idx = arg->internal.idx; + + if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */ + argc--; argv++; idx++; + } + + next_one: + if( !argc ) { /* no more args */ + arg->r_opt = 0; + goto leave; /* ready */ + } + + s = *argv; + arg->internal.last = s; + + if( arg->internal.stopped && (arg->flags & (1<<1)) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else if( arg->internal.stopped ) { /* ready */ + arg->r_opt = 0; + goto leave; + } + else if( *s == '-' && s[1] == '-' ) { /* long option */ + char *argpos; + + arg->internal.inarg = 0; + if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */ + arg->internal.stopped = 1; + argc--; argv++; idx++; + goto next_one; + } + + argpos = strchr( s+2, '=' ); + if( argpos ) + *argpos = 0; + i = find_long_option( arg, opts, s+2 ); + if( argpos ) + *argpos = '='; + + if( i < 0 && !strcmp( "help", s+2) ) { + if( !(arg->flags & (1<<6)) ) { + show_help(opts, arg->flags); + } + } + else if( i < 0 && !strcmp( "version", s+2) ) { + if( !(arg->flags & (1<<6)) ) { + show_version(); + exit(0); + } + } + else if( i < 0 && !strcmp( "warranty", s+2) ) { + puts( strusage(16) ); + exit(0); + } + else if( i < 0 && !strcmp( "dump-options", s+2) ) { + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt ) + printf( "--%s\n", opts[i].long_opt ); + } + fputs("--dump-options\n--help\n--version\n--warranty\n", stdout ); + exit(0); + } + + if( i == -2 ) /* ambiguous option */ + arg->r_opt = -8; + else if( i == -1 ) { + arg->r_opt = -2; + arg->r.ret_str = s+2; + } + else + arg->r_opt = opts[i].short_opt; + if( i < 0 ) + ; + else if( (opts[i].flags & 7) ) { + if( argpos ) { + s2 = argpos+1; + if( !*s2 ) + s2 = NULL; + } + else + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + if( !argpos ) { + argc--; argv++; idx++; /* skip one */ + } + } + } + else { /* does not take an argument */ + if( argpos ) + arg->r_type = -6; /* argument not expected */ + else + arg->r_type = 0; + } + argc--; argv++; idx++; /* set to next one */ + } + else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */ + int dash_kludge = 0; + i = 0; + if( !arg->internal.inarg ) { + arg->internal.inarg++; + if( arg->flags & (1<<5) ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) { + dash_kludge=1; + break; + } + } + } + s += arg->internal.inarg; + + if( !dash_kludge ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].short_opt == *s ) + break; + } + + if( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) { + if( !(arg->flags & (1<<6)) ) { + show_help(opts, arg->flags); + } + } + + arg->r_opt = opts[i].short_opt; + if( !opts[i].short_opt ) { + arg->r_opt = (opts[i].flags & 256)? -7:-2; + arg->internal.inarg++; /* point to the next arg */ + arg->r.ret_str = s; + } + else if( (opts[i].flags & 7) ) { + if( s[1] && !dash_kludge ) { + s2 = s+1; + set_opt_arg(arg, opts[i].flags, s2); + } + else { + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + argc--; argv++; idx++; /* skip one */ + } + } + s = "x"; /* so that !s[1] yields false */ + } + else { /* does not take an argument */ + arg->r_type = 0; + arg->internal.inarg++; /* point to the next arg */ + } + if( !s[1] || dash_kludge ) { /* no more concatenated short options */ + arg->internal.inarg = 0; + argc--; argv++; idx++; + } + } + else if( arg->flags & (1<<2) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else { + arg->internal.stopped = 1; /* stop option processing */ + goto next_one; + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal.idx = idx; + return arg->r_opt; +} + + + +static int +set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) +{ + int base = (flags & 16)? 0 : 10; + + switch( arg->r_type = (flags & 7) ) { + case 1: /* takes int argument */ + arg->r.ret_int = (int)strtol(s,NULL,base); + return 0; + case 3: /* takes long argument */ + arg->r.ret_long= strtol(s,NULL,base); + return 0; + case 4: /* takes ulong argument */ + arg->r.ret_ulong= strtoul(s,NULL,base); + return 0; + case 2: /* takes string argument */ + default: + arg->r.ret_str = s; + return 1; + } +} + + +static size_t +long_opt_strlen( ARGPARSE_OPTS *o ) +{ + size_t n = strlen(o->long_opt); + + if( o->description && *o->description == '|' ) { + const char *s; + + s=o->description+1; + if( *s != '=' ) + n++; + for(; *s && *s != '|'; s++ ) + n++; + } + return n; +} + +/**************** + * Print formatted help. The description string has some special + * meanings: + * - A description string which is "@" suppresses help output for + * this option + * - a description,ine which starts with a '@' and is followed by + * any other characters is printed as is; this may be used for examples + * ans such. + * - A description which starts with a '|' outputs the string between this + * bar and the next one as arguments of the long option. + */ +static void +show_help( ARGPARSE_OPTS *opts, unsigned flags ) +{ + const char *s; + + show_version(); + putchar('\n'); + s = strusage(41); + puts(s); + if( opts[0].description ) { /* auto format the option description */ + int i,j, indent; + /* get max. length of long options */ + for(i=indent=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt ) + if( !opts[i].description || *opts[i].description != '@' ) + if( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) + indent = j; + } + /* example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + if( *opts[0].description != '@' ) + puts("Options:"); + for(i=0; opts[i].short_opt; i++ ) { + s = _( opts[i].description ); + if( s && *s== '@' && !s[1] ) /* hide this line */ + continue; + if( s && *s == '@' ) { /* unindented comment only line */ + for(s++; *s; s++ ) { + if( *s == '\n' ) { + if( s[1] ) + putchar('\n'); + } + else + putchar(*s); + } + putchar('\n'); + continue; + } + + j = 3; + if( opts[i].short_opt < 256 ) { + printf(" -%c", opts[i].short_opt ); + if( !opts[i].long_opt ) { + if(s && *s == '|' ) { + putchar(' '); j++; + for(s++ ; *s && *s != '|'; s++, j++ ) + putchar(*s); + if( *s ) + s++; + } + } + } + else + fputs(" ", stdout); + if( opts[i].long_opt ) { + j += printf("%c --%s", opts[i].short_opt < 256?',':' ', + opts[i].long_opt ); + if(s && *s == '|' ) { + if( *++s != '=' ) { + putchar(' '); + j++; + } + for( ; *s && *s != '|'; s++, j++ ) + putchar(*s); + if( *s ) + s++; + } + fputs(" ", stdout); + j += 3; + } + for(;j < indent; j++ ) + putchar(' '); + if( s ) { + if( *s && j > indent ) { + putchar('\n'); + for(j=0;j < indent; j++ ) + putchar(' '); + } + for(; *s; s++ ) { + if( *s == '\n' ) { + if( s[1] ) { + putchar('\n'); + for(j=0;j < indent; j++ ) + putchar(' '); + } + } + else + putchar(*s); + } + } + putchar('\n'); + } + if( flags & 32 ) + puts("\n(A single dash may be used instead of the double ones)"); + } + if( (s=strusage(19)) ) { /* bug reports to ... */ + putchar('\n'); + fputs(s, stdout); + } + fflush(stdout); + exit(0); +} + +static void +show_version() +{ + const char *s; + int i; + /* version line */ + fputs(strusage(11), stdout); + if( (s=strusage(12)) ) + printf(" (%s)", s ); + printf(" %s\n", strusage(13) ); + /* additional version lines */ + for(i=20; i < 30; i++ ) + if( (s=strusage(i)) ) + printf("%s\n", s ); + /* copyright string */ + if( (s=strusage(14)) ) + printf("%s\n", s ); + /* copying conditions */ + if( (s=strusage(15)) ) + fputs(s, stdout); + /* thanks */ + if( (s=strusage(18)) ) + fputs(s, stdout); + /* additional program info */ + for(i=30; i < 40; i++ ) + if( (s=strusage(i)) ) + fputs( (const byte*)s, stdout); + fflush(stdout); +} + + +void +usage( int level ) +{ + if( !level ) { + fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13), + strusage(14) ); + fflush(stderr); + } + else if( level == 1 ) { + fputs(strusage(40),stderr); + exit(2); + } + else if( level == 2 ) { + puts(strusage(41)); + exit(0); + } +} + +/* Level + * 0: Copyright String auf stderr ausgeben + * 1: Kurzusage auf stderr ausgeben und beenden + * 2: Langusage auf stdout ausgeben und beenden + * 11: name of program + * 12: optional name of package which includes this program. + * 13: version string + * 14: copyright string + * 15: Short copying conditions (with LFs) + * 16: Long copying conditions (with LFs) + * 17: Optional printable OS name + * 18: Optional thanks list (with LFs) + * 19: Bug report info + *20..29: Additional lib version strings. + *30..39: Additional program info (with LFs) + * 40: short usage note (with LF) + * 41: long usage note (with LF) + */ +const char * +default_strusage( int level ) +{ + const char *p = NULL; + switch( level ) { + case 11: p = "foo"; break; + case 13: p = "0.0"; break; + case 14: p = "Copyright (C) 2002 Free Software Foundation, Inc."; break; + case 15: p = +"This program comes with ABSOLUTELY NO WARRANTY.\n" +"This is free software, and you are welcome to redistribute it\n" +"under certain conditions. See the file COPYING for details.\n"; break; + case 16: p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; + break; + case 40: /* short and long usage */ + case 41: p = ""; break; + } + + return p; +} + + + +#ifdef TEST +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +}opt; + +int +main(int argc, char **argv) +{ + ARGPARSE_OPTS opts[] = { + { 'v', "verbose", 0 , "Laut sein"}, + { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"}, + { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"}, + { 'o', "output", 2 }, + { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" }, + { 'm', "my-option", 1|8 }, + { 500, "a-long-option", 0 }, + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 }; + int i; + + while( ArgParse( &pargs, opts) ) { + switch( pargs.r_opt ) { + case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break; + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break; + default : pargs.err = 1; break; /* force warning output */ + } + } + for(i=0; i < argc; i++ ) + printf("%3d -> (%s)\n", i, argv[i] ); + puts("Options:"); + if( opt.verbose ) + printf(" verbose=%d\n", opt.verbose ); + if( opt.debug ) + printf(" debug=%d\n", opt.debug ); + if( opt.outfile ) + printf(" outfile=`%s'\n", opt.outfile ); + if( opt.crf ) + printf(" crffile=`%s'\n", opt.crf ); + if( opt.myopt ) + printf(" myopt=%d\n", opt.myopt ); + if( opt.a_long_one ) + printf(" a-long-one=%d\n", opt.a_long_one ); + if( opt.echo ) + printf(" echo=%d\n", opt.echo ); + return 0; +} +#endif + +/**** bottom of file ****/ diff --git a/util/dotlock.c b/util/dotlock.c new file mode 100644 index 000000000..fac825450 --- /dev/null +++ b/util/dotlock.c @@ -0,0 +1,420 @@ +/* dotlock.c - dotfile locking + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 <config.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#if !defined (HAVE_DOSISH_SYSTEM) +#include <sys/utsname.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include "types.h" +#include "util.h" +#include "memory.h" + +struct dotlock_handle { + struct dotlock_handle *next; + char *tname; /* name of lockfile template */ + char *lockname; /* name of the real lockfile */ + int locked; /* lock status */ + int disable; /* locking */ +}; + + +static volatile DOTLOCK all_lockfiles; +static int never_lock; + +static int read_lockfile( const char *name ); + +void +disable_dotlock(void) +{ + never_lock = 1; +} + +/**************** + * Create a lockfile with the given name and return an object of + * type DOTLOCK which may be used later to actually do the lock. + * A cleanup routine gets installed to cleanup left over locks + * or other files used together with the lockmechanism. + * Althoug the function is called dotlock, this does not necessarily + * mean that real lockfiles are used - the function may decide to + * use fcntl locking. Calling the function with NULL only install + * the atexit handler and maybe used to assure that the cleanup + * is called after all other atexit handlers. + * + * Notes: This function creates a lock file in the same directory + * as file_to_lock with the name "file_to_lock.lock" + * A temporary file ".#lk.<hostname>.pid[.threadid] is used. + * This function does nothing for Windoze. + */ +DOTLOCK +create_dotlock( const char *file_to_lock ) +{ + static int initialized; + DOTLOCK h; + int fd = -1; + char pidstr[16]; + #if !defined (HAVE_DOSISH_SYSTEM) + struct utsname utsbuf; + #endif + const char *nodename; + const char *dirpart; + int dirpartlen; + + if( !initialized ) { + atexit( remove_lockfiles ); + initialized = 1; + } + if( !file_to_lock ) + return NULL; + + h = m_alloc_clear( sizeof *h ); + if( never_lock ) { + h->disable = 1; + #ifdef _REENTRANT + /* fixme: aquire mutex on all_lockfiles */ + #endif + h->next = all_lockfiles; + all_lockfiles = h; + return h; + } + + +#if !defined (HAVE_DOSISH_SYSTEM) + sprintf( pidstr, "%10d\n", (int)getpid() ); + /* fixme: add the hostname to the second line (FQDN or IP addr?) */ + + /* create a temporary file */ + if( uname( &utsbuf ) ) + nodename = "unknown"; + else + nodename = utsbuf.nodename; + +#ifdef __riscos__ + { + char *iter = (char *) nodename; + for (; iter[0]; iter++) + if (iter[0] == '.') + iter[0] = '/'; + } +#endif /* __riscos__ */ + + if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) { + dirpart = EXTSEP_S; + dirpartlen = 1; + } + else { + dirpartlen = dirpart - file_to_lock; + dirpart = file_to_lock; + } + + #ifdef _REENTRANT + /* fixme: aquire mutex on all_lockfiles */ + #endif + h->next = all_lockfiles; + all_lockfiles = h; + + h->tname = m_alloc( dirpartlen + 6+30+ strlen(nodename) + 11 ); +#ifndef __riscos__ + sprintf( h->tname, "%.*s/.#lk%p.%s.%d", + dirpartlen, dirpart, h, nodename, (int)getpid() ); +#else /* __riscos__ */ + sprintf( h->tname, "%.*s.lk%p/%s/%d", + dirpartlen, dirpart, h, nodename, (int)getpid() ); +#endif /* __riscos__ */ + + do { + errno = 0; + fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL, + S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); + } while( fd == -1 && errno == EINTR ); + if( fd == -1 ) { + all_lockfiles = h->next; + log_error( "failed to create temporary file `%s': %s\n", + h->tname, strerror(errno)); + m_free(h->tname); + m_free(h); + return NULL; + } + if( write(fd, pidstr, 11 ) != 11 ) { + all_lockfiles = h->next; + #ifdef _REENTRANT + /* release mutex */ + #endif + log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) ); + close(fd); + unlink(h->tname); + m_free(h->tname); + m_free(h); + return NULL; + } + if( close(fd) ) { + all_lockfiles = h->next; + #ifdef _REENTRANT + /* release mutex */ + #endif + log_error( "error closing `%s': %s\n", h->tname, strerror(errno)); + unlink(h->tname); + m_free(h->tname); + m_free(h); + return NULL; + } + + #ifdef _REENTRANT + /* release mutex */ + #endif +#endif + h->lockname = m_alloc( strlen(file_to_lock) + 6 ); + strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); + return h; +} + +static int +maybe_deadlock( DOTLOCK h ) +{ + DOTLOCK r; + + for( r=all_lockfiles; r; r = r->next ) { + if( r != h && r->locked ) + return 1; + } + return 0; +} + +/**************** + * Do a lock on H. A TIMEOUT of 0 returns immediately, + * -1 waits forever (hopefully not), other + * values are timeouts in milliseconds. + * Returns: 0 on success + */ +int +make_dotlock( DOTLOCK h, long timeout ) +{ +#if defined (HAVE_DOSISH_SYSTEM) + return 0; +#else + int pid; + const char *maybe_dead=""; + int backoff=0; + + if( h->disable ) { + return 0; + } + + if( h->locked ) { +#ifndef __riscos__ + log_debug("oops, `%s' is already locked\n", h->lockname ); +#endif /* !__riscos__ */ + return 0; + } + + for(;;) { +#ifndef __riscos__ + if( !link(h->tname, h->lockname) ) { + /* fixme: better use stat to check the link count */ + h->locked = 1; + return 0; /* okay */ + } + if( errno != EEXIST ) { + log_error( "lock not made: link() failed: %s\n", strerror(errno) ); + return -1; + } +#else /* __riscos__ */ + if( !renamefile(h->tname, h->lockname) ) { + h->locked = 1; + return 0; /* okay */ + } + if( errno != EEXIST ) { + log_error( "lock not made: rename() failed: %s\n", strerror(errno) ); + return -1; + } +#endif /* __riscos__ */ + if( (pid = read_lockfile(h->lockname)) == -1 ) { + if( errno != ENOENT ) { + log_info("cannot read lockfile\n"); + return -1; + } + log_info( "lockfile disappeared\n"); + continue; + } + else if( pid == getpid() ) { + log_info( "Oops: lock already held by us\n"); + h->locked = 1; + return 0; /* okay */ + } + else if( kill(pid, 0) && errno == ESRCH ) { +#ifndef __riscos__ + maybe_dead = " - probably dead"; + #if 0 /* we should not do this without checking the permissions */ + /* and the hostname */ + log_info( "removing stale lockfile (created by %d)", pid ); + #endif +#else /* __riscos__ */ + /* we are *pretty* sure that the other task is dead and therefore + we remove the other lock file */ + maybe_dead = " - probably dead - removing lock"; + unlink(h->lockname); +#endif /* __riscos__ */ + } + if( timeout == -1 ) { + struct timeval tv; + log_info( "waiting for lock (held by %d%s) %s...\n", + pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":""); + + + /* can't use sleep, cause signals may be blocked */ + tv.tv_sec = 1 + backoff; + tv.tv_usec = 0; + select(0, NULL, NULL, NULL, &tv); + if( backoff < 10 ) + backoff++ ; + } + else + return -1; + } + /*not reached */ +#endif +} + + +/**************** + * release a lock + * Returns: 0 := success + */ +int +release_dotlock( DOTLOCK h ) +{ +#if defined (HAVE_DOSISH_SYSTEM) + return 0; +#else + int pid; + + if( h->disable ) { + return 0; + } + + if( !h->locked ) { + log_debug("oops, `%s' is not locked\n", h->lockname ); + return 0; + } + + pid = read_lockfile( h->lockname ); + if( pid == -1 ) { + log_error( "release_dotlock: lockfile error\n"); + return -1; + } + if( pid != getpid() ) { + log_error( "release_dotlock: not our lock (pid=%d)\n", pid); + return -1; + } +#ifndef __riscos__ + if( unlink( h->lockname ) ) { + log_error( "release_dotlock: error removing lockfile `%s'", + h->lockname); + return -1; + } +#else /* __riscos__ */ + if( renamefile(h->lockname, h->tname) ) { + log_error( "release_dotlock: error renaming lockfile `%s' to `%s'", + h->lockname, h->tname); + return -1; + } +#endif /* __riscos__ */ + /* fixme: check that the link count is now 1 */ + h->locked = 0; + return 0; +#endif +} + + +/**************** + * Read the lock file and return the pid, returns -1 on error. + */ +static int +read_lockfile( const char *name ) +{ + #if defined (HAVE_DOSISH_SYSTEM) + return 0; + #else + int fd, pid; + char pidstr[16]; + + if( (fd = open(name, O_RDONLY)) == -1 ) { + int e = errno; + log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) ); + errno = e; + return -1; + } + if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */ + log_debug("error reading lockfile `%s'", name ); + close(fd); + errno = 0; + return -1; + } + pidstr[10] = 0; /* terminate pid string */ + close(fd); + pid = atoi(pidstr); +#ifndef __riscos__ + if( !pid || pid == -1 ) { +#else /* __riscos__ */ + if( (!pid && riscos_getpid()) || pid == -1 ) { +#endif /* __riscos__ */ + log_error("invalid pid %d in lockfile `%s'", pid, name ); + errno = 0; + return -1; + } + return pid; + #endif +} + + +void +remove_lockfiles() +{ + #if !defined (HAVE_DOSISH_SYSTEM) + DOTLOCK h, h2; + + h = all_lockfiles; + all_lockfiles = NULL; + + while( h ) { + h2 = h->next; + if( !h->disable ) { + if( h->locked ) + unlink( h->lockname ); + unlink(h->tname); + m_free(h->tname); + m_free(h->lockname); + } + m_free(h); + h = h2; + } + #endif +} + diff --git a/util/errors.c b/util/errors.c index d3eb2f172..25d5a088a 100644 --- a/util/errors.c +++ b/util/errors.c @@ -1,5 +1,5 @@ /* errors.c - error strings - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,7 +23,6 @@ #include <stdlib.h> #include <stdarg.h> -#include <gcrypt.h> #include "errors.h" #include "i18n.h" @@ -43,12 +42,12 @@ strerror( int n ) #endif /* !HAVE_STRERROR */ const char * -gpg_errstr( int err ) +g10_errstr( int err ) { static char buf[50]; const char *p; - #define X(n,s) case GPGERR_##n : p = s; break; + #define X(n,s) case G10ERR_##n : p = s; break; switch( err ) { case -1: p = "eof"; break; case 0: p = "okay"; break; @@ -101,13 +100,12 @@ gpg_errstr( int err ) X(NETWORK ,N_("network error")) X(SELFTEST_FAILED,"selftest failed") X(NOT_ENCRYPTED ,N_("not encrypted")) - default: /* pass on to libgcrypt */ - if( err >= 0 ) /* pass on to libgcrypt */ - p = gcry_strerror(err); /* fimxe: how do we handle i18n? */ - else { - p = buf; sprintf(buf, "gpgerr=%d", err); break; - } - break; + X(NOT_PROCESSED ,N_("not processed")) + /* the key cannot be used for a specific usage */ + X(UNU_PUBKEY ,N_("unusable public key")) + X(UNU_SECKEY ,N_("unusable secret key")) + X(KEYSERVER ,N_("keyserver error")) + default: p = buf; sprintf(buf, "g10err=%d", err); break; } #undef X return _(p); diff --git a/util/fileutil.c b/util/fileutil.c index 39268da74..76eacfb80 100644 --- a/util/fileutil.c +++ b/util/fileutil.c @@ -25,7 +25,10 @@ #include <string.h> #include <assert.h> #include <unistd.h> -#include <gcrypt.h> +#ifdef __riscos__ +#include <kernel.h> +#include <swis.h> +#endif /* __riscos__ */ #include "util.h" #include "memory.h" #include "ttyio.h" @@ -40,16 +43,16 @@ make_basename(const char *filepath) { char *p; - if ( !(p=strrchr(filepath, '/')) ) + if ( !(p=strrchr(filepath, DIRSEP_C)) ) #ifdef HAVE_DRIVE_LETTERS if ( !(p=strrchr(filepath, '\\')) ) if ( !(p=strrchr(filepath, ':')) ) #endif { - return gcry_xstrdup(filepath); + return m_strdup(filepath); } - return gcry_xstrdup(p+1); + return m_strdup(p+1); } @@ -67,17 +70,17 @@ make_dirname(const char *filepath) int dirname_length; char *p; - if ( !(p=strrchr(filepath, '/')) ) + if ( !(p=strrchr(filepath, DIRSEP_C)) ) #ifdef HAVE_DRIVE_LETTERS if ( !(p=strrchr(filepath, '\\')) ) if ( !(p=strrchr(filepath, ':')) ) #endif { - return gcry_xstrdup("."); + return m_strdup(EXTSEP_S); } dirname_length = p-filepath; - dirname = gcry_xmalloc(dirname_length+1); + dirname = m_alloc(dirname_length+1); strncpy(dirname, filepath, dirname_length); dirname[dirname_length] = 0; @@ -104,20 +107,30 @@ make_filename( const char *first_part, ... ) n += strlen(s) + 1; va_end(arg_ptr); +#ifndef __riscos__ home = NULL; - if( *first_part == '~' && first_part[1] == '/' + if( *first_part == '~' && first_part[1] == DIRSEP_C && (home = getenv("HOME")) && *home ) n += strlen(home); - - name = gcry_xmalloc(n); + name = m_alloc(n); p = home ? stpcpy(stpcpy(name,home), first_part+1) : stpcpy(name, first_part); +#else /* __riscos__ */ + name = m_alloc(n); + p = stpcpy(name, first_part); +#endif /* __riscos__ */ va_start( arg_ptr, first_part ) ; while( (s=va_arg(arg_ptr, const char *)) ) - p = stpcpy(stpcpy(p,"/"), s); + p = stpcpy(stpcpy(p, DIRSEP_S), s); va_end(arg_ptr); +#ifndef __riscos__ return name; +#else /* __riscos__ */ + p = gstrans(name); + m_free(name); + return p; +#endif /* __riscos__ */ } @@ -127,11 +140,26 @@ compare_filenames( const char *a, const char *b ) /* ? check whether this is an absolute filename and * resolve symlinks? */ +#ifndef __riscos__ #ifdef HAVE_DRIVE_LETTERS - return stricmp(a,b); + return ascii_strcasecmp(a,b); #else return strcmp(a,b); #endif +#else /* __riscos__ */ + int c = 0; + char *abuf, *bbuf; + + abuf = gstrans(a); + bbuf = gstrans(b); + + c = strcasecmp (abuf, bbuf); + + m_free(abuf); + m_free(bbuf); + + return c; +#endif /* __riscos__ */ } @@ -156,4 +184,55 @@ print_fname_stdin( const char *s ) return s; } +/**************** + * Check if the file is compressed. + **/ +int +is_file_compressed( const char *s, int *ret_rc ) +{ + IOBUF a; + byte buf[4]; + int i, rc = 0; + + struct magic_compress_s { + size_t len; + byte magic[4]; + } magic[] = { + { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ + { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ + { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ + }; + + if ( !s || *s == '-' || !ret_rc ) + return 0; /* We can't check stdin or no file was given */ + + a = iobuf_open( s ); + if ( a == NULL ) { + *ret_rc = G10ERR_OPEN_FILE; + return 0; + } + + if ( iobuf_get_filelength( a ) < 4 ) { + *ret_rc = 0; + goto leave; + } + + if ( iobuf_read( a, buf, 4 ) == -1 ) { + *ret_rc = G10ERR_READ_FILE; + goto leave; + } + + for ( i = 0; i < DIM( magic ); i++ ) { + if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) { + *ret_rc = 0; + rc = 1; + break; + } + } + +leave: + iobuf_close( a ); + return rc; +} + diff --git a/util/g10u.c b/util/g10u.c new file mode 100644 index 000000000..2ce3a4e36 --- /dev/null +++ b/util/g10u.c @@ -0,0 +1,40 @@ +/* g10u.c - Wrapper for utility functions + * Copyright (C) 1998 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi.h" +#include "util.h" + + +/* FIXME: The modules should use functions from libgcrypt */ + +const char *g10u_revision_string(int dummy) { return "$Revision$"; } + + +void *g10_malloc( size_t n ) { return m_alloc( n ); } +void *g10_calloc( size_t n ) { return m_alloc_clear( n ); } +void *g10_malloc_secure( size_t n ) { return m_alloc_secure( n ); } +void *g10_calloc_secure( size_t n ) { return m_alloc_secure_clear( n ); } +void *g10_realloc( void *a, size_t n ) { return m_realloc( a, n ); } +void g10_free( void *p ) { m_free( p ); } +char *g10_strdup( const char * a) { return m_strdup( a ); } + diff --git a/util/http.c b/util/http.c index 81bf91ded..23556b7bd 100644 --- a/util/http.c +++ b/util/http.c @@ -1,5 +1,5 @@ /* http.c - HTTP protocol handler - * Copyright (C) 1999, 2000 Free Software Foundation, Inc. + * Copyright (C) 1999, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -26,18 +26,18 @@ #include <ctype.h> #include <errno.h> -#ifndef HAVE_DOSISH_SYSTEM /* fixme: add support W32 sockets */ - -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <gcrypt.h> +#ifdef __MINGW32__ + #include <windows.h> +#else + #include <unistd.h> + #include <sys/types.h> + #include <sys/socket.h> + #include <sys/time.h> + #include <time.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <netdb.h> +#endif #include "util.h" #include "iobuf.h" @@ -45,6 +45,20 @@ #include "http.h" +#ifdef __riscos__ + #define HTTP_PROXY_ENV "GnuPG$HttpProxy" + #define HTTP_PROXY_ENV_PRINTABLE "<GnuPG$HttpProxy>" +#else + #define HTTP_PROXY_ENV "http_proxy" + #define HTTP_PROXY_ENV_PRINTABLE "$http_proxy" +#endif + +#ifdef __MINGW32__ +#define sock_close(a) closesocket(a) +#else +#define sock_close(a) close(a) +#endif + #define MAX_LINELEN 20000 /* max. length of a HTTP line */ #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ @@ -69,6 +83,38 @@ static int parse_response( HTTP_HD hd ); static int connect_server( const char *server, ushort port ); static int write_server( int sock, const char *data, size_t length ); +#ifdef __MINGW32__ +static void +deinit_sockets (void) +{ + WSACleanup(); +} + +static void +init_sockets (void) +{ + static int initialized; + static WSADATA wsdata; + + if (initialized) + return; + + if( WSAStartup( 0x0101, &wsdata ) ) { + log_error ("error initializing socket library: ec=%d\n", + (int)WSAGetLastError () ); + return; + } + if( wsdata.wVersion < 0x0001 ) { + log_error ("socket library version is %x.%x - but 1.1 needed\n", + LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion)); + WSACleanup(); + return; + } + atexit ( deinit_sockets ); + initialized = 1; +} +#endif /*__MINGW32__*/ + int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, @@ -77,7 +123,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, int rc; if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) ) - return GPGERR_INV_ARG; + return G10ERR_INV_ARG; /* initialize the handle */ memset( hd, 0, sizeof *hd ); @@ -90,15 +136,15 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, if( !rc ) { rc = send_request( hd ); if( !rc ) { - hd->fp_write = iobuf_fdopen( hd->sock , "w" ); + hd->fp_write = iobuf_sockopen( hd->sock , "w" ); if( hd->fp_write ) return 0; - rc = GPGERR_GENERAL; + rc = G10ERR_GENERAL; } } if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - close( hd->sock ); + sock_close( hd->sock ); iobuf_close( hd->fp_read ); iobuf_close( hd->fp_write); release_parsed_uri( hd->uri ); @@ -111,8 +157,9 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, void http_start_data( HTTP_HD hd ) { + iobuf_flush ( hd->fp_write ); if( !hd->in_data ) { - iobuf_put( hd->fp_write, '\n' ); + write_server (hd->sock, "\r\n", 2); hd->in_data = 1; } } @@ -124,19 +171,22 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status ) int rc; http_start_data( hd ); /* make sure that we are in the data */ - iobuf_flush( hd->fp_write ); - hd->sock = dup( hd->sock ); + #if 0 + hd->sock = dup( hd->sock ); if( hd->sock == -1 ) - return GPGERR_GENERAL; - iobuf_close( hd->fp_write ); + return G10ERR_GENERAL; + #endif + iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */ + iobuf_close (hd->fp_write); hd->fp_write = NULL; - shutdown( hd->sock, 1 ); + if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) ) + shutdown( hd->sock, 1 ); hd->in_data = 0; - hd->fp_read = iobuf_fdopen( hd->sock , "r" ); + hd->fp_read = iobuf_sockopen( hd->sock , "r" ); if( !hd->fp_read ) - return GPGERR_GENERAL; + return G10ERR_GENERAL; rc = parse_response( hd ); if( !rc && ret_status ) @@ -171,11 +221,11 @@ http_close( HTTP_HD hd ) if( !hd || !hd->initialized ) return; if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - close( hd->sock ); + sock_close( hd->sock ); iobuf_close( hd->fp_read ); iobuf_close( hd->fp_write ); release_parsed_uri( hd->uri ); - gcry_free( hd->buffer ); + m_free( hd->buffer ); hd->initialized = 0; } @@ -189,7 +239,7 @@ http_close( HTTP_HD hd ) static int parse_uri( PARSED_URI *ret_uri, const char *uri ) { - *ret_uri = gcry_xcalloc( 1, sizeof(**ret_uri) + strlen(uri) ); + *ret_uri = m_alloc_clear( sizeof(**ret_uri) + strlen(uri) ); strcpy( (*ret_uri)->buffer, uri ); return do_parse_uri( *ret_uri, 0 ); } @@ -203,9 +253,9 @@ release_parsed_uri( PARSED_URI uri ) for( r = uri->query; r; r = r2 ) { r2 = r->next; - gcry_free( r ); + m_free( r ); } - gcry_free( uri ); + m_free( uri ); } } @@ -225,27 +275,28 @@ do_parse_uri( PARSED_URI uri, int only_local_part ) /* a quick validity check */ if( strspn( p, VALID_URI_CHARS) != n ) - return GPGERR_BAD_URI; /* invalid characters found */ + return G10ERR_BAD_URI; /* invalid characters found */ if( !only_local_part ) { /* find the scheme */ if( !(p2 = strchr( p, ':' ) ) || p2 == p ) - return GPGERR_BAD_URI; /* No scheme */ + return G10ERR_BAD_URI; /* No scheme */ *p2++ = 0; strlwr( p ); uri->scheme = p; + uri->port = 80; if( !strcmp( uri->scheme, "http" ) ) ; else if( !strcmp( uri->scheme, "x-hkp" ) ) /* same as HTTP */ - ; + uri->port = 11371; else - return GPGERR_INVALID_URI; /* Unsupported scheme */ + return G10ERR_INVALID_URI; /* Unsupported scheme */ p = p2; /* find the hostname */ if( *p != '/' ) - return GPGERR_INVALID_URI; /* does not start with a slash */ + return G10ERR_INVALID_URI; /* does not start with a slash */ p++; if( *p == '/' ) { /* there seems to be a hostname */ @@ -258,13 +309,12 @@ do_parse_uri( PARSED_URI uri, int only_local_part ) *p3++ = 0; uri->port = atoi( p3 ); } - else - uri->port = 80; + uri->host = p; if( (n = remove_escapes( uri->host )) < 0 ) - return GPGERR_BAD_URI; + return G10ERR_BAD_URI; if( n != strlen( p ) ) - return GPGERR_BAD_URI; /* hostname with a Nul in it */ + return G10ERR_BAD_URI; /* hostname with a Nul in it */ p = p2 ? p2 : NULL; } } /* end global URI part */ @@ -281,9 +331,9 @@ do_parse_uri( PARSED_URI uri, int only_local_part ) uri->path = p; if( (n = remove_escapes( p )) < 0 ) - return GPGERR_BAD_URI; + return G10ERR_BAD_URI; if( n != strlen( p ) ) - return GPGERR_BAD_URI; /* path with a Nul in it */ + return G10ERR_BAD_URI; /* path with a Nul in it */ p = p2 ? p2 : NULL; if( !p || !*p ) /* we don't have a query string */ @@ -297,7 +347,7 @@ do_parse_uri( PARSED_URI uri, int only_local_part ) if( (p2 = strchr( p, '&' )) ) *p2++ = 0; if( !(elem = parse_tuple( p )) ) - return GPGERR_BAD_URI; + return G10ERR_BAD_URI; *tail = elem; tail = &elem->next; @@ -397,7 +447,7 @@ parse_tuple( byte *string ) return NULL; /* bad URI */ if( n != strlen( p ) ) return NULL; /* name with a Nul in it */ - tuple = gcry_xcalloc( 1, sizeof *tuple ); + tuple = m_alloc_clear( sizeof *tuple ); tuple->name = p; if( !p2 ) { /* we have only the name, so we assume an empty value string */ @@ -406,7 +456,7 @@ parse_tuple( byte *string ) } else { /* name and value */ if( (n = remove_escapes( p2 )) < 0 ) { - gcry_free( tuple ); + m_free( tuple ); return NULL; /* bad URI */ } tuple->value = p2; @@ -433,14 +483,15 @@ send_request( HTTP_HD hd ) port = hd->uri->port? hd->uri->port : 80; if( (hd->flags & HTTP_FLAG_TRY_PROXY) - && (http_proxy = getenv( "http_proxy" )) ) { + && (http_proxy = getenv( HTTP_PROXY_ENV )) ) { PARSED_URI uri; rc = parse_uri( &uri, http_proxy ); if (rc) { - log_error("invalid $http_proxy: %s\n", gpg_errstr(rc)); + log_error("invalid " HTTP_PROXY_ENV_PRINTABLE ": %s\n", + g10_errstr(rc)); release_parsed_uri( uri ); - return GPGERR_NETWORK; + return G10ERR_NETWORK; } hd->sock = connect_server( *uri->host? uri->host : "localhost", uri->port? uri->port : 80 ); @@ -450,10 +501,10 @@ send_request( HTTP_HD hd ) hd->sock = connect_server( server, port ); if( hd->sock == -1 ) - return GPGERR_NETWORK; + return G10ERR_NETWORK; p = build_rel_path( hd->uri ); - request = gcry_xmalloc( strlen(p) + 20 ); + request = m_alloc( strlen(server) + strlen(p) + 50 ); if( http_proxy ) { sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n", hd->req_type == HTTP_REQ_GET ? "GET" : @@ -468,10 +519,10 @@ send_request( HTTP_HD hd ) hd->req_type == HTTP_REQ_POST? "POST": "OOPS", *p == '/'? "":"/", p ); } - gcry_free(p); + m_free(p); rc = write_server( hd->sock, request, strlen(request) ); - gcry_free( request ); + m_free( request ); return rc; } @@ -502,7 +553,7 @@ build_rel_path( PARSED_URI uri ) n++; /* now allocate and copy */ - p = rel_path = gcry_xmalloc( n ); + p = rel_path = m_alloc( n ); n = insert_escapes( p, uri->path, "%;?&" ); p += n; /* todo: add params */ @@ -608,13 +659,13 @@ start_server() if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) { log_error("bind to port 11371 failed: %s\n", strerror(errno) ); - close( fd ); + sock_close( fd ); return -1; } if( listen( fd, 5 ) ) { log_error("listen failed: %s\n", strerror(errno) ); - close( fd ); + sock_close( fd ); return -1; } @@ -647,7 +698,7 @@ start_server() fclose(fp); exit(0); } - close( client ); + sock_close( client ); } @@ -660,9 +711,51 @@ start_server() static int connect_server( const char *server, ushort port ) { + int sd; +#ifdef __MINGW32__ + struct hostent *hp; + struct sockaddr_in ad; + unsigned long l; + + init_sockets (); + + memset (&ad, 0, sizeof(ad)); + ad.sin_family = AF_INET; + ad.sin_port = htons(port); + + if( (l = inet_addr (server)) != SOCKET_ERROR ) { + memcpy (&ad.sin_addr, &l, sizeof(l)); + } + else if( (hp = gethostbyname (server)) ) { + if( hp->h_addrtype != AF_INET ) { + log_error ("%s: unknown address family\n", server); + return -1; + } + if ( hp->h_length != 4 ) { + log_error ("%s: illegal address length\n", server); + return -1; + } + memcpy (&ad.sin_addr, hp->h_addr, hp->h_length); + } + else { + log_error ("%s: host not found: ec=%d\n", + server, (int)WSAGetLastError ()); + return -1; + } + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + log_error ("error creating socket: ex=%d\n", + (int)WSAGetLastError ()); + return -1; + } + + if( connect (sd, (struct sockaddr *)&ad, sizeof (ad) ) ) { + sock_close (sd); + return -1; + } +#else struct sockaddr_in addr; struct hostent *host; - int sd; addr.sin_family = AF_INET; addr.sin_port = htons(port); @@ -677,10 +770,10 @@ connect_server( const char *server, ushort port ) return -1; if( connect( sd, (struct sockaddr *)&addr, sizeof addr) == -1 ) { - close(sd); + sock_close(sd); return -1; } - +#endif return sd; } @@ -688,11 +781,20 @@ connect_server( const char *server, ushort port ) static int write_server( int sock, const char *data, size_t length ) { - int nleft, nwritten; + int nleft; nleft = length; while( nleft > 0 ) { - nwritten = write( sock, data, nleft ); + #ifdef __MINGW32__ + int nwritten; + + nwritten = send (sock, data, nleft, 0); + if ( nwritten == SOCKET_ERROR ) { + log_info ("write failed: ec=%d\n", (int)WSAGetLastError ()); + return G10ERR_NETWORK; + } + #else + int nwritten = write( sock, data, nleft ); if( nwritten == -1 ) { if( errno == EINTR ) continue; @@ -705,8 +807,9 @@ write_server( int sock, const char *data, size_t length ) continue; } log_info("write failed: %s\n", strerror(errno)); - return GPGERR_NETWORK; + return G10ERR_NETWORK; } + #endif nleft -=nwritten; data += nwritten; } @@ -714,8 +817,6 @@ write_server( int sock, const char *data, size_t length ) return 0; } -#endif /* HAVE_DOSISH_SYSTEM */ - /**** Test code ****/ #ifdef TEST @@ -742,7 +843,7 @@ main(int argc, char **argv) rc = parse_uri( &uri, *argv ); if( rc ) { - log_error("`%s': %s\n", *argv, gpg_errstr(rc)); + log_error("`%s': %s\n", *argv, g10_errstr(rc)); release_parsed_uri( uri ); return 1; } @@ -767,7 +868,7 @@ main(int argc, char **argv) rc = http_open_document( &hd, *argv, 0 ); if( rc ) { - log_error("can't get `%s': %s\n", *argv, gpg_errstr(rc)); + log_error("can't get `%s': %s\n", *argv, g10_errstr(rc)); return 1; } log_info("open_http_document succeeded; status=%u\n", hd.status_code ); diff --git a/util/iobuf.c b/util/iobuf.c index 5f70694c2..5df2d6975 100644 --- a/util/iobuf.c +++ b/util/iobuf.c @@ -1,5 +1,5 @@ /* iobuf.c - file handling - * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,33 +23,89 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <ctype.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <unistd.h> -#include <gcrypt.h> #ifdef HAVE_DOSISH_SYSTEM - #include <fcntl.h> /* for setmode() */ + #include <windows.h> #endif +#ifdef __riscos__ +#include <kernel.h> +#include <swis.h> +#endif /* __riscos__ */ #include "memory.h" #include "util.h" #include "iobuf.h" +#undef FILE_FILTER_USES_STDIO -#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64) - #define fopen(a,b) fopen64 ((a),(b)) - #define fstat(a,b) fstat64 ((a),(b)) +#ifdef HAVE_DOSISH_SYSTEM + #define USE_SETMODE 1 #endif +#ifdef FILE_FILTER_USES_STDIO + #define my_fileno(a) fileno ((a)) + #define my_fopen_ro(a,b) fopen ((a),(b)) + #define my_fopen(a,b) fopen ((a),(b)) + typedef FILE *FILEP_OR_FD; + #define INVALID_FP NULL + #define FILEP_OR_FD_FOR_STDIN (stdin) + #define FILEP_OR_FD_FOR_STDOUT (stdout) + typedef struct { + FILE *fp; /* open file handle */ + int keep_open; + int no_cache; + int print_only_name; /* flags indicating that fname is not a real file*/ + char fname[1]; /* name of the file */ + } file_filter_ctx_t ; +#else + #define my_fileno(a) (a) + #define my_fopen_ro(a,b) fd_cache_open ((a),(b)) + #define my_fopen(a,b) direct_open ((a),(b)) + #ifdef HAVE_DOSISH_SYSTEM + typedef HANDLE FILEP_OR_FD; + #define INVALID_FP ((HANDLE)-1) + #define FILEP_OR_FD_FOR_STDIN (GetStdHandle (STD_INPUT_HANDLE)) + #define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE)) + #undef USE_SETMODE + #else + typedef int FILEP_OR_FD; + #define INVALID_FP (-1) + #define FILEP_OR_FD_FOR_STDIN (0) + #define FILEP_OR_FD_FOR_STDOUT (1) + #endif + typedef struct { + FILEP_OR_FD fp; /* open file handle */ + int keep_open; + int no_cache; + int eof_seen; + int print_only_name; /* flags indicating that fname is not a real file*/ + char fname[1]; /* name of the file */ + } file_filter_ctx_t ; + + struct close_cache_s { + struct close_cache_s *next; + FILEP_OR_FD fp; + char fname[1]; + }; + typedef struct close_cache_s *CLOSE_CACHE; + static CLOSE_CACHE close_cache; +#endif - +#ifdef __MINGW32__ typedef struct { - FILE *fp; /* open file handle */ + int sock; + int keep_open; + int no_cache; + int eof_seen; int print_only_name; /* flags indicating that fname is not a real file*/ char fname[1]; /* name of the file */ -} file_filter_ctx_t ; - +} sock_filter_ctx_t ; +#endif /*__MINGW32__*/ /* The first partial length header block must be of size 512 * to make it easier (and efficienter) we use a min. block size of 512 @@ -68,8 +124,185 @@ typedef struct { int eof; } block_filter_ctx_t; +static int special_names_enabled; static int underflow(IOBUF a); +static int translate_file_handle ( int fd, int for_write ); + +#ifndef FILE_FILTER_USES_STDIO + +/* + * Invalidate (i.e. close) a cached iobuf + */ +static void +fd_cache_invalidate (const char *fname) +{ + CLOSE_CACHE cc; + + assert (fname); + if( DBG_IOBUF ) + log_debug ("fd_cache_invalidate (%s)\n", fname); + + for (cc=close_cache; cc; cc = cc->next ) { + if ( cc->fp != INVALID_FP && !strcmp (cc->fname, fname) ) { + if( DBG_IOBUF ) + log_debug (" did (%s)\n", cc->fname); + #ifdef HAVE_DOSISH_SYSTEM + CloseHandle (cc->fp); + #else + close(cc->fp); + #endif + cc->fp = INVALID_FP; + } + } +} + + + +static FILEP_OR_FD +direct_open (const char *fname, const char *mode) +{ +#ifdef HAVE_DOSISH_SYSTEM + unsigned long da, cd, sm; + HANDLE hfile; + + /* Note, that we do not handle all mode combinations */ + + /* According to the ReactOS source it seems that open() of the + * standard MSW32 crt does open the file in share mode which is + * something new for MS applications ;-) + */ + if ( strchr (mode, '+') ) { + fd_cache_invalidate (fname); + da = GENERIC_READ|GENERIC_WRITE; + cd = OPEN_EXISTING; + sm = FILE_SHARE_READ | FILE_SHARE_WRITE; + } + else if ( strchr (mode, 'w') ) { + fd_cache_invalidate (fname); + da = GENERIC_WRITE; + cd = CREATE_ALWAYS; + sm = FILE_SHARE_WRITE; + } + else { + da = GENERIC_READ; + cd = OPEN_EXISTING; + sm = FILE_SHARE_READ; + } + + hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL); + return hfile; +#else + int oflag; + int cflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + + /* Note, that we do not handle all mode combinations */ + if ( strchr (mode, '+') ) { + fd_cache_invalidate (fname); + oflag = O_RDWR; + } + else if ( strchr (mode, 'w') ) { + fd_cache_invalidate (fname); + oflag = O_WRONLY | O_CREAT | O_TRUNC; + } + else { + oflag = O_RDONLY; + } +#ifndef __riscos__ + return open (fname, oflag, cflag ); +#else + { + struct stat buf; + int rc = stat( fname, &buf ); + + /* Don't allow iobufs on directories */ + if( !rc && S_ISDIR(buf.st_mode) && !S_ISREG(buf.st_mode) ) + return __set_errno( EISDIR ); + else + return open( fname, oflag, cflag ); + } +#endif +#endif +} + + +/* + * Instead of closing an FD we keep it open and cache it for later reuse + * Note that this caching strategy only works if the process does not chdir. + */ +static void +fd_cache_close (const char *fname, FILEP_OR_FD fp) +{ + CLOSE_CACHE cc; + + assert (fp); + if ( !fname || !*fname ) { +#ifdef HAVE_DOSISH_SYSTEM + CloseHandle (fp); +#else + close(fp); +#endif + if( DBG_IOBUF ) + log_debug ("fd_cache_close (%p) real\n", (void*)fp); + return; + } + /* try to reuse a slot */ + for (cc=close_cache; cc; cc = cc->next ) { + if ( cc->fp == INVALID_FP && !strcmp (cc->fname, fname) ) { + cc->fp = fp; + if( DBG_IOBUF ) + log_debug ("fd_cache_close (%s) used existing slot\n", fname); + return; + } + } + /* add a new one */ + if( DBG_IOBUF ) + log_debug ("fd_cache_close (%s) new slot created\n", fname); + cc = m_alloc_clear (sizeof *cc + strlen (fname)); + strcpy (cc->fname, fname); + cc->fp = fp; + cc->next = close_cache; + close_cache = cc; +} + +/* + * Do an direct_open on FNAME but first try to reuse one from the fd_cache + */ +static FILEP_OR_FD +fd_cache_open (const char *fname, const char *mode) +{ + CLOSE_CACHE cc; + + assert (fname); + for (cc=close_cache; cc; cc = cc->next ) { + if ( cc->fp != INVALID_FP && !strcmp (cc->fname, fname) ) { + FILEP_OR_FD fp = cc->fp; + cc->fp = INVALID_FP; + if( DBG_IOBUF ) + log_debug ("fd_cache_open (%s) using cached fp\n", fname); + #ifdef HAVE_DOSISH_SYSTEM + if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff ) { + log_error ("rewind file failed on handle %p: ec=%d\n", + fp, (int)GetLastError () ); + fp = INVALID_FP; + } + #else + if ( lseek (fp, 0, SEEK_SET) == (off_t)-1 ) { + log_error("can't rewind fd %d: %s\n", fp, strerror(errno) ); + fp = INVALID_FP; + } + #endif + return fp; + } + } + if( DBG_IOBUF ) + log_debug ("fd_cache_open (%s) not cached\n", fname); + return direct_open (fname, mode); +} + + +#endif /*FILE_FILTER_USES_STDIO*/ + /**************** * Read data from a file into buf which has an allocated length of *LEN. @@ -87,7 +320,7 @@ static int underflow(IOBUF a); * buffer, and should be set to the number of bytes * which were put into the buffer. The function * returns 0 to indicate success, -1 on EOF and - * GPGERR_xxxxx for other errors. + * G10ERR_xxxxx for other errors. * * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff. * *RET_LAN is the number of bytes in BUF. @@ -99,59 +332,258 @@ static int file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) { file_filter_ctx_t *a = opaque; - FILE *fp = a->fp; + FILEP_OR_FD f = a->fp; size_t size = *ret_len; size_t nbytes = 0; int rc = 0; +#ifdef FILE_FILTER_USES_STDIO if( control == IOBUFCTRL_UNDERFLOW ) { assert( size ); /* need a buffer */ - if ( feof(fp)) { /* On terminals you could easiely read as many EOFs as you call */ + if ( feof(f)) { /* On terminals you could easiely read as many EOFs as you call */ rc = -1; /* fread() or fgetc() repeatly. Every call will block until you press */ *ret_len = 0; /* CTRL-D. So we catch this case before we call fread() again. */ } else { - clearerr( fp ); - nbytes = fread( buf, 1, size, fp ); - if( feof(fp) && !nbytes ) + clearerr( f ); + nbytes = fread( buf, 1, size, f ); + if( feof(f) && !nbytes ) { rc = -1; /* okay: we can return EOF now. */ - else if( ferror(fp) && errno != EPIPE ) { + } + else if( ferror(f) && errno != EPIPE ) { log_error("%s: read error: %s\n", a->fname, strerror(errno)); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; } *ret_len = nbytes; } } else if( control == IOBUFCTRL_FLUSH ) { if( size ) { - clearerr( fp ); - nbytes = fwrite( buf, 1, size, fp ); - if( ferror(fp) ) { + clearerr( f ); + nbytes = fwrite( buf, 1, size, f ); + if( ferror(f) ) { log_error("%s: write error: %s\n", a->fname, strerror(errno)); - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; } } *ret_len = nbytes; } else if( control == IOBUFCTRL_INIT ) { + a->keep_open = a->no_cache = 0; } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "file_filter"; } else if( control == IOBUFCTRL_FREE ) { - if( fp != stdin && fp != stdout ) { + if( f != stdin && f != stdout ) { if( DBG_IOBUF ) - log_debug("%s: close fd %d\n", a->fname, fileno(fp) ); - fclose(fp); + log_debug("%s: close fd %d\n", a->fname, fileno(f) ); + if (!a->keep_open) + fclose(f); } - fp = NULL; - gcry_free(a); /* we can free our context now */ + f = NULL; + m_free(a); /* we can free our context now */ } +#else /* !stdio implementation */ + if( control == IOBUFCTRL_UNDERFLOW ) { + assert( size ); /* need a buffer */ + if ( a->eof_seen) { + rc = -1; + *ret_len = 0; + } + else { + #ifdef HAVE_DOSISH_SYSTEM + unsigned long nread; + + nbytes = 0; + if ( !ReadFile ( f, buf, size, &nread, NULL ) ) { + int ec = (int)GetLastError (); + if ( ec != ERROR_BROKEN_PIPE ) { + log_error("%s: read error: ec=%d\n", a->fname, ec); + rc = G10ERR_READ_FILE; + } + } + else if ( !nread ) { + a->eof_seen = 1; + rc = -1; + } + else { + nbytes = nread; + } + + #else + + int n; + + nbytes = 0; + do { + n = read ( f, buf, size ); + } while (n == -1 && errno == EINTR ); + if ( n == -1 ) { /* error */ + if (errno != EPIPE) { + log_error("%s: read error: %s\n", + a->fname, strerror(errno)); + rc = G10ERR_READ_FILE; + } + } + else if ( !n ) { /* eof */ + a->eof_seen = 1; + rc = -1; + } + else { + nbytes = n; + } + #endif + *ret_len = nbytes; + } + } + else if( control == IOBUFCTRL_FLUSH ) { + if( size ) { + #ifdef HAVE_DOSISH_SYSTEM + byte *p = buf; + unsigned long n; + + nbytes = size; + do { + if ( size && !WriteFile ( f, p, nbytes, &n, NULL) ) { + int ec = (int)GetLastError (); + log_error("%s: write error: ec=%d\n", a->fname, ec); + rc = G10ERR_WRITE_FILE; + break; + } + p += n; + nbytes -= n; + } while ( nbytes ); + nbytes = p - buf; + #else + byte *p = buf; + int n; + + nbytes = size; + do { + do { + n = write ( f, p, nbytes ); + } while ( n == -1 && errno == EINTR ); + if ( n > 0 ) { + p += n; + nbytes -= n; + } + } while ( n != -1 && nbytes ); + if( n == -1 ) { + log_error("%s: write error: %s\n", a->fname, strerror(errno)); + rc = G10ERR_WRITE_FILE; + } + nbytes = p - buf; + #endif + } + *ret_len = nbytes; + } + else if ( control == IOBUFCTRL_INIT ) { + a->eof_seen = 0; + a->keep_open = 0; + a->no_cache = 0; + } + else if ( control == IOBUFCTRL_DESC ) { + *(char**)buf = "file_filter(fd)"; + } + else if ( control == IOBUFCTRL_FREE ) { + #ifdef HAVE_DOSISH_SYSTEM + if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) { + if( DBG_IOBUF ) + log_debug("%s: close handle %p\n", a->fname, f ); + if (!a->keep_open) + fd_cache_close (a->no_cache?NULL:a->fname, f); + } + #else + if ( (int)f != 0 && (int)f != 1 ) { + if( DBG_IOBUF ) + log_debug("%s: close fd %d\n", a->fname, f ); + if (!a->keep_open) + fd_cache_close (a->no_cache?NULL:a->fname, f); + } + f = INVALID_FP; + #endif + m_free (a); /* we can free our context now */ + } +#endif /* !stdio implementation */ return rc; } +#ifdef __MINGW32__ +/* Becuase sockets are an special object under Lose32 we have to + * use a special filter */ +static int +sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) +{ + sock_filter_ctx_t *a = opaque; + size_t size = *ret_len; + size_t nbytes = 0; + int rc = 0; + + if( control == IOBUFCTRL_UNDERFLOW ) { + assert( size ); /* need a buffer */ + if ( a->eof_seen) { + rc = -1; + *ret_len = 0; + } + else { + int nread; + + nread = recv ( a->sock, buf, size, 0 ); + if ( nread == SOCKET_ERROR ) { + int ec = (int)WSAGetLastError (); + log_error("socket read error: ec=%d\n", ec); + rc = G10ERR_READ_FILE; + } + else if ( !nread ) { + a->eof_seen = 1; + rc = -1; + } + else { + nbytes = nread; + } + *ret_len = nbytes; + } + } + else if( control == IOBUFCTRL_FLUSH ) { + if( size ) { + byte *p = buf; + int n; + + nbytes = size; + do { + n = send (a->sock, p, nbytes, 0); + if ( n == SOCKET_ERROR ) { + int ec = (int)WSAGetLastError (); + log_error("socket write error: ec=%d\n", ec); + rc = G10ERR_WRITE_FILE; + break; + } + p += n; + nbytes -= n; + } while ( nbytes ); + nbytes = p - buf; + } + *ret_len = nbytes; + } + else if ( control == IOBUFCTRL_INIT ) { + a->eof_seen = 0; + a->keep_open = 0; + a->no_cache = 0; + } + else if ( control == IOBUFCTRL_DESC ) { + *(char**)buf = "sock_filter"; + } + else if ( control == IOBUFCTRL_FREE ) { + if (!a->keep_open) + closesocket (a->sock); + m_free (a); /* we can free our context now */ + } + return rc; +} +#endif /*__MINGW32__*/ /**************** * This is used to implement the block write mode. @@ -191,7 +623,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) } else if( (c = iobuf_get(chain)) == -1 ) { log_error("block_filter: 1st length byte missing\n"); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; break; } if( c < 192 ) { @@ -208,7 +640,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) a->size = (c - 192) * 256; if( (c = iobuf_get(chain)) == -1 ) { log_error("block_filter: 2nd length byte missing\n"); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; break; } a->size += c + 192; @@ -226,7 +658,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) a->size |= iobuf_get(chain) << 8; if( (c = iobuf_get(chain)) == -1 ) { log_error("block_filter: invalid 4 byte length\n"); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; break; } a->size |= c; @@ -243,7 +675,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) a->size |= c; if( c == -1 ) { log_error("block_filter: error reading length info\n"); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; } if( !a->size ) { a->eof = 1; @@ -261,7 +693,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if( c == -1 ) c = 0; log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n", a, (ulong)size+c, (ulong)a->size+c); - rc = GPGERR_READ_FILE; + rc = G10ERR_READ_FILE; } else { size -= c; @@ -281,7 +713,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if( nbytes < OP_MIN_PARTIAL_CHUNK ) { /* not enough to write a partial block out; so we store it*/ if( !a->buffer ) - a->buffer = gcry_xmalloc( OP_MIN_PARTIAL_CHUNK ); + a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK ); memcpy( a->buffer + a->buflen, buf, size ); a->buflen += size; } @@ -303,14 +735,14 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if( (n=a->buflen) ) { /* write stuff from the buffer */ assert( n == OP_MIN_PARTIAL_CHUNK); if( iobuf_write(chain, a->buffer, n ) ) - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; a->buflen = 0; nbytes -= n; } if( (n = nbytes) > blen ) n = blen; if( n && iobuf_write(chain, p, n ) ) - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; p += n; nbytes -= n; } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK ); @@ -319,7 +751,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) assert( !a->buflen ); assert( nbytes < OP_MIN_PARTIAL_CHUNK ); if( !a->buffer ) - a->buffer = gcry_xmalloc( OP_MIN_PARTIAL_CHUNK ); + a->buffer = m_alloc( OP_MIN_PARTIAL_CHUNK ); memcpy( a->buffer, p, nbytes ); a->buflen = nbytes; } @@ -348,7 +780,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if( n > avail ) n = avail; if( iobuf_write(chain, p, n ) ) - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; a->count += n; p += n; size -= n; @@ -405,9 +837,9 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) rc = iobuf_write(chain, a->buffer, len ); if( rc ) { log_error("block_filter: write error: %s\n",strerror(errno)); - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; } - gcry_free( a->buffer ); a->buffer = NULL; a->buflen = 0; + m_free( a->buffer ); a->buffer = NULL; a->buflen = 0; } else { iobuf_writebyte(chain, 0); @@ -419,7 +851,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) } if( DBG_IOBUF ) log_debug("free block_filter %p\n", a ); - gcry_free(a); /* we can free our context now */ + m_free(a); /* we can free our context now */ } return rc; @@ -463,9 +895,9 @@ iobuf_alloc(int use, size_t bufsize) IOBUF a; static int number=0; - a = gcry_xcalloc( 1,sizeof *a); + a = m_alloc_clear(sizeof *a); a->use = use; - a->d.buf = gcry_xmalloc( bufsize ); + a->d.buf = m_alloc( bufsize ); a->d.size = bufsize; a->no = ++number; a->subno = 0; @@ -474,17 +906,16 @@ iobuf_alloc(int use, size_t bufsize) return a; } - int -iobuf_close( IOBUF a ) +iobuf_close ( IOBUF a ) { IOBUF a2; - size_t dummy_len = 0; + size_t dummy_len=0; int rc=0; if( a && a->directfp ) { fclose( a->directfp ); - gcry_free( a->real_fname ); + m_free( a->real_fname ); if( DBG_IOBUF ) log_debug("iobuf_close -> %p\n", a->directfp ); return 0; @@ -493,35 +924,37 @@ iobuf_close( IOBUF a ) for( ; a && !rc ; a = a2 ) { a2 = a->chain; if( a->use == 2 && (rc=iobuf_flush(a)) ) - log_error("iobuf_flush failed on close: %s\n", gpg_errstr(rc)); + log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc)); if( DBG_IOBUF ) log_debug("iobuf-%d.%d: close `%s'\n", a->no, a->subno, a->desc ); if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain, NULL, &dummy_len)) ) - log_error("IOBUFCTRL_FREE failed on close: %s\n", gpg_errstr(rc) ); - gcry_free(a->real_fname); - gcry_free(a->d.buf); - gcry_free(a); + log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) ); + m_free(a->real_fname); + if (a->d.buf) { + memset (a->d.buf, 0, a->d.size); /* erase the buffer */ + m_free(a->d.buf); + } + m_free(a); } return rc; } - int iobuf_cancel( IOBUF a ) { const char *s; IOBUF a2; int rc; - #ifdef HAVE_DOSISH_SYSTEM + #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) char *remove_name = NULL; #endif if( a && a->use == 2 ) { s = iobuf_get_real_fname(a); if( s && *s ) { - #ifdef HAVE_DOSISH_SYSTEM + #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) remove_name = m_strdup ( s ); #else remove(s); @@ -538,7 +971,7 @@ iobuf_cancel( IOBUF a ) } rc = iobuf_close(a); - #ifdef HAVE_DOSISH_SYSTEM + #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) if ( remove_name ) { /* Argg, MSDOS does not allow to remove open files. So * we have to do it here */ @@ -549,6 +982,7 @@ iobuf_cancel( IOBUF a ) return rc; } + /**************** * create a temporary iobuf, which can be used to collect stuff * in an iobuf and later be written by iobuf_write_temp() to another @@ -576,6 +1010,32 @@ iobuf_temp_with_content( const char *buffer, size_t length ) return a; } +void +iobuf_enable_special_filenames ( int yes ) +{ + special_names_enabled = yes; +} + +/* + * see whether the filename has the for "-&nnnn", where n is a + * non-zero number. + * Returns this number or -1 if it is not the case. + */ +static int +check_special_filename ( const char *fname ) +{ + if ( special_names_enabled + && fname && *fname == '-' && fname[1] == '&' ) { + int i; + + fname += 2; + for (i=0; isdigit (fname[i]); i++ ) + ; + if ( !fname[i] ) + return atoi (fname); + } + return -1; +} /**************** * Create a head iobuf for reading from a file @@ -585,35 +1045,38 @@ IOBUF iobuf_open( const char *fname ) { IOBUF a; - FILE *fp; + FILEP_OR_FD fp; file_filter_ctx_t *fcx; size_t len; int print_only = 0; + int fd; if( !fname || (*fname=='-' && !fname[1]) ) { - fp = stdin; - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(fp) , O_BINARY ); + fp = FILEP_OR_FD_FOR_STDIN; + #ifdef USE_SETMODE + setmode ( my_fileno(fp) , O_BINARY ); #endif fname = "[stdin]"; print_only = 1; } - else if( !(fp = fopen(fname, "rb")) ) + else if ( (fd = check_special_filename ( fname )) != -1 ) + return iobuf_fdopen ( translate_file_handle (fd,0), "rb" ); + else if( (fp = my_fopen_ro(fname, "rb")) == INVALID_FP ) return NULL; a = iobuf_alloc(1, 8192 ); - fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); fcx->fp = fp; fcx->print_only_name = print_only; strcpy(fcx->fname, fname ); if( !print_only ) - a->real_fname = gcry_xstrdup( fname ); + a->real_fname = m_strdup( fname ); a->filter = file_filter; a->filter_ov = fcx; file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); if( DBG_IOBUF ) log_debug("iobuf-%d.%d: open `%s' fd=%d\n", - a->no, a->subno, fname, fileno(fcx->fp) ); + a->no, a->subno, fname, (int)my_fileno(fcx->fp) ); return a; } @@ -626,14 +1089,18 @@ IOBUF iobuf_fdopen( int fd, const char *mode ) { IOBUF a; - FILE *fp; + FILEP_OR_FD fp; file_filter_ctx_t *fcx; size_t len; +#ifdef FILE_FILTER_USES_STDIO if( !(fp = fdopen(fd, mode)) ) return NULL; +#else + fp = (FILEP_OR_FD)fd; +#endif a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 ); - fcx = gcry_xmalloc( sizeof *fcx + 20 ); + fcx = m_alloc( sizeof *fcx + 20 ); fcx->fp = fp; fcx->print_only_name = 1; sprintf(fcx->fname, "[fd %d]", fd ); @@ -643,7 +1110,34 @@ iobuf_fdopen( int fd, const char *mode ) file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); if( DBG_IOBUF ) log_debug("iobuf-%d.%d: fdopen `%s'\n", a->no, a->subno, fcx->fname ); + iobuf_ioctl (a,3,1,NULL); /* disable fd caching */ + return a; +} + +IOBUF +iobuf_sockopen ( int fd, const char *mode ) +{ + IOBUF a; +#ifdef __MINGW32__ + sock_filter_ctx_t *scx; + size_t len; + + a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 ); + scx = m_alloc( sizeof *scx + 25 ); + scx->sock = fd; + scx->print_only_name = 1; + sprintf(scx->fname, "[sock %d]", fd ); + a->filter = sock_filter; + a->filter_ov = scx; + sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); + sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len ); + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname); + iobuf_ioctl (a,3,1,NULL); /* disable fd caching */ +#else + a = iobuf_fdopen (fd, mode); +#endif return a; } @@ -654,28 +1148,31 @@ IOBUF iobuf_create( const char *fname ) { IOBUF a; - FILE *fp; + FILEP_OR_FD fp; file_filter_ctx_t *fcx; size_t len; int print_only = 0; + int fd; if( !fname || (*fname=='-' && !fname[1]) ) { - fp = stdout; - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(fp) , O_BINARY ); + fp = FILEP_OR_FD_FOR_STDOUT; + #ifdef USE_SETMODE + setmode ( my_fileno(fp) , O_BINARY ); #endif fname = "[stdout]"; print_only = 1; } - else if( !(fp = fopen(fname, "wb")) ) + else if ( (fd = check_special_filename ( fname )) != -1 ) + return iobuf_fdopen ( translate_file_handle (fd, 1), "wb" ); + else if( (fp = my_fopen(fname, "wb")) == INVALID_FP ) return NULL; a = iobuf_alloc(2, 8192 ); - fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); fcx->fp = fp; fcx->print_only_name = print_only; strcpy(fcx->fname, fname ); if( !print_only ) - a->real_fname = gcry_xstrdup( fname ); + a->real_fname = m_strdup( fname ); a->filter = file_filter; a->filter_ov = fcx; file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); @@ -689,7 +1186,9 @@ iobuf_create( const char *fname ) /**************** * append to an iobuf; if the file does not exist, create it. * cannot be used for stdout. + * Note: This is not used. */ +#if 0 /* not used */ IOBUF iobuf_append( const char *fname ) { @@ -700,13 +1199,13 @@ iobuf_append( const char *fname ) if( !fname ) return NULL; - else if( !(fp = fopen(fname, "ab")) ) + else if( !(fp = my_fopen(fname, "ab")) ) return NULL; a = iobuf_alloc(2, 8192 ); - fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); fcx->fp = fp; strcpy(fcx->fname, fname ); - a->real_fname = gcry_xstrdup( fname ); + a->real_fname = m_strdup( fname ); a->filter = file_filter; a->filter_ov = fcx; file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); @@ -716,24 +1215,25 @@ iobuf_append( const char *fname ) return a; } +#endif IOBUF iobuf_openrw( const char *fname ) { IOBUF a; - FILE *fp; + FILEP_OR_FD fp; file_filter_ctx_t *fcx; size_t len; if( !fname ) return NULL; - else if( !(fp = fopen(fname, "r+b")) ) + else if( (fp = my_fopen(fname, "r+b")) == INVALID_FP ) return NULL; a = iobuf_alloc(2, 8192 ); - fcx = gcry_xmalloc( sizeof *fcx + strlen(fname) ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); fcx->fp = fp; strcpy(fcx->fname, fname ); - a->real_fname = gcry_xstrdup( fname ); + a->real_fname = m_strdup( fname ); a->filter = file_filter; a->filter_ov = fcx; file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); @@ -745,41 +1245,61 @@ iobuf_openrw( const char *fname ) } - -/**************** - * You can overwrite the normal iobuf behaviour by using this function. - * If used the iobuf is a simple wrapper around stdio. - * NULL if an error occures and sets errno - */ -IOBUF -iobuf_fopen( const char *fname, const char *mode ) +int +iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval ) { - IOBUF a; - FILE *fp; - int print_only = 0; - - if( !fname || (*fname=='-' && !fname[1]) ) { - fp = stdin; - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(fp) , O_BINARY ); - #endif - fname = "[stdin]"; - print_only = 1; + if ( cmd == 1 ) { /* keep system filepointer/descriptor open */ + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: ioctl `%s' keep=%d\n", + a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval ); + for( ; a; a = a->chain ) + if( !a->chain && a->filter == file_filter ) { + file_filter_ctx_t *b = a->filter_ov; + b->keep_open = intval; + return 0; + } + #ifdef __MINGW32__ + else if( !a->chain && a->filter == sock_filter ) { + sock_filter_ctx_t *b = a->filter_ov; + b->keep_open = intval; + return 0; + } + #endif + } + else if ( cmd == 2 ) { /* invalidate cache */ + if( DBG_IOBUF ) + log_debug("iobuf-*.*: ioctl `%s' invalidate\n", + ptrval? (char*)ptrval:"?"); + if ( !a && !intval && ptrval ) { + #ifndef FILE_FILTER_USES_STDIO + fd_cache_invalidate (ptrval); + #endif + return 0; + } + } + else if ( cmd == 3 ) { /* disallow/allow caching */ + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: ioctl `%s' no_cache=%d\n", + a? a->no:-1, a?a->subno:-1, a?a->desc:"?", intval ); + for( ; a; a = a->chain ) + if( !a->chain && a->filter == file_filter ) { + file_filter_ctx_t *b = a->filter_ov; + b->no_cache = intval; + return 0; + } + #ifdef __MINGW32__ + else if( !a->chain && a->filter == sock_filter ) { + sock_filter_ctx_t *b = a->filter_ov; + b->no_cache = intval; + return 0; + } + #endif } - else if( !(fp = fopen(fname, mode) ) ) - return NULL; - a = iobuf_alloc(1, 8192 ); - a->directfp = fp; - a->real_fname = gcry_xstrdup( fname ); - - if( DBG_IOBUF ) - log_debug("iobuf_fopen -> %p\n", a->directfp ); - return a; + return -1; } - /**************** * Register an i/o filter. */ @@ -811,12 +1331,12 @@ iobuf_push_filter2( IOBUF a, * The contents of the buffers are transferred to the * new stream. */ - b = gcry_xmalloc(sizeof *b); + b = m_alloc(sizeof *b); memcpy(b, a, sizeof *b ); /* fixme: it is stupid to keep a copy of the name at every level * but we need the name somewhere because the name known by file_filter * may have been released when we need the name of the file */ - b->real_fname = a->real_fname? gcry_xstrdup(a->real_fname):NULL; + b->real_fname = a->real_fname? m_strdup(a->real_fname):NULL; /* remove the filter stuff from the new stream */ a->filter = NULL; a->filter_ov = NULL; @@ -826,12 +1346,12 @@ iobuf_push_filter2( IOBUF a, a->use = 2; /* make a write stream from a temp stream */ if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */ - b->d.buf = gcry_xmalloc( a->d.size ); + b->d.buf = m_alloc( a->d.size ); b->d.len = 0; b->d.start = 0; } else { /* allocate a fresh buffer for the new stream */ - a->d.buf = gcry_xmalloc( a->d.size ); + a->d.buf = m_alloc( a->d.size ); a->d.len = 0; a->d.start = 0; } @@ -859,7 +1379,7 @@ iobuf_push_filter2( IOBUF a, /* now we can initialize the new function if we have one */ if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain, NULL, &dummy_len)) ) - log_error("IOBUFCTRL_INIT failed: %s\n", gpg_errstr(rc) ); + log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) ); return rc; } @@ -882,10 +1402,10 @@ pop_filter( IOBUF a, int (*f)(void *opaque, int control, if( !a->filter ) { /* this is simple */ b = a->chain; assert(b); - gcry_free(a->d.buf); - gcry_free(a->real_fname); + m_free(a->d.buf); + m_free(a->real_fname); memcpy(a,b, sizeof *a); - gcry_free(b); + m_free(b); return 0; } for(b=a ; b; b = b->chain ) @@ -896,17 +1416,17 @@ pop_filter( IOBUF a, int (*f)(void *opaque, int control, /* flush this stream if it is an output stream */ if( a->use == 2 && (rc=iobuf_flush(b)) ) { - log_error("iobuf_flush failed in pop_filter: %s\n", gpg_errstr(rc)); + log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc)); return rc; } /* and tell the filter to free it self */ if( b->filter && (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain, NULL, &dummy_len)) ) { - log_error("IOBUFCTRL_FREE failed: %s\n", gpg_errstr(rc) ); + log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); return rc; } if( b->filter_ov && b->filter_ov_owner ) { - gcry_free( b->filter_ov ); + m_free( b->filter_ov ); b->filter_ov = NULL; } @@ -919,10 +1439,10 @@ pop_filter( IOBUF a, int (*f)(void *opaque, int control, * a flush has been done on the to be removed entry */ b = a->chain; - gcry_free(a->d.buf); - gcry_free(a->real_fname); + m_free(a->d.buf); + m_free(a->real_fname); memcpy(a,b, sizeof *a); - gcry_free(b); + m_free(b); if( DBG_IOBUF ) log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno ); } @@ -957,10 +1477,10 @@ underflow(IOBUF a) if( DBG_IOBUF ) log_debug("iobuf-%d.%d: pop `%s' in underflow\n", a->no, a->subno, a->desc ); - gcry_free(a->d.buf); - gcry_free(a->real_fname); + m_free(a->d.buf); + m_free(a->real_fname); memcpy(a, b, sizeof *a); - gcry_free(b); + m_free(b); print_chain(a); } else @@ -1011,9 +1531,9 @@ underflow(IOBUF a) /* and tell the filter to free itself */ if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain, NULL, &dummy_len)) ) - log_error("IOBUFCTRL_FREE failed: %s\n", gpg_errstr(rc) ); + log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); if( a->filter_ov && a->filter_ov_owner ) { - gcry_free( a->filter_ov ); + m_free( a->filter_ov ); a->filter_ov = NULL; } a->filter = NULL; @@ -1026,10 +1546,10 @@ underflow(IOBUF a) log_debug("iobuf-%d.%d: pop `%s' in underflow (!len)\n", a->no, a->subno, a->desc ); print_chain(a); - gcry_free(a->d.buf); - gcry_free(a->real_fname); + m_free(a->d.buf); + m_free(a->real_fname); memcpy(a,b, sizeof *a); - gcry_free(b); + m_free(b); print_chain(a); } } @@ -1063,16 +1583,15 @@ iobuf_flush(IOBUF a) if( a->directfp ) return 0; - /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/ if( a->use == 3 ) { /* increase the temp buffer */ char *newbuf; size_t newsize = a->d.size + 8192; log_debug("increasing temp iobuf from %lu to %lu\n", (ulong)a->d.size, (ulong)newsize ); - newbuf = gcry_xmalloc( newsize ); + newbuf = m_alloc( newsize ); memcpy( newbuf, a->d.buf, a->d.len ); - gcry_free(a->d.buf); + m_free(a->d.buf); a->d.buf = newbuf; a->d.size = newsize; return 0; @@ -1085,7 +1604,7 @@ iobuf_flush(IOBUF a) rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len ); if( !rc && len != a->d.len ) { log_info("iobuf_flush did not write all!\n"); - rc = GPGERR_WRITE_FILE; + rc = G10ERR_WRITE_FILE; } else if( rc ) a->error = 1; @@ -1108,7 +1627,7 @@ iobuf_readbyte(IOBUF a) if( a->unget.buf ) { if( a->unget.start < a->unget.len ) return a->unget.buf[a->unget.start++]; - gcry_free(a->unget.buf); + m_free(a->unget.buf); a->unget.buf = NULL; a->nofast &= ~2; } @@ -1301,7 +1820,7 @@ iobuf_flush_temp( IOBUF temp ) * Setting the limit to 0 disables this feature. */ void -iobuf_set_limit( IOBUF a, unsigned long nlimit ) +iobuf_set_limit( IOBUF a, off_t nlimit ) { if( nlimit ) a->nofast |= 1; @@ -1317,44 +1836,38 @@ iobuf_set_limit( IOBUF a, unsigned long nlimit ) /**************** * Return the length of an open file */ -u32 +off_t iobuf_get_filelength( IOBUF a ) { -#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64) - struct stat64 st; -#else struct stat st; -#endif if( a->directfp ) { FILE *fp = a->directfp; - if( !fstat(fileno(fp), &st) ) { - #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64) - if( st.st_size >= IOBUF_FILELENGTH_LIMIT ) - return IOBUF_FILELENGTH_LIMIT; - #endif - return (u32)st.st_size; - } + if( !fstat(fileno(fp), &st) ) + return st.st_size; log_error("fstat() failed: %s\n", strerror(errno) ); return 0; } - /* Hmmm: file_filter may have already been removed */ for( ; a; a = a->chain ) if( !a->chain && a->filter == file_filter ) { file_filter_ctx_t *b = a->filter_ov; - FILE *fp = b->fp; + FILEP_OR_FD fp = b->fp; + + #if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO) + ulong size; - if( !fstat(fileno(fp), &st) ) { - #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64) - if( st.st_size >= IOBUF_FILELENGTH_LIMIT ) - return IOBUF_FILELENGTH_LIMIT; - #endif + if ( (size=GetFileSize (fp, NULL)) != 0xffffffff ) + return size; + log_error ("GetFileSize for handle %p failed: ec=%d\n", + fp, (int)GetLastError () ); + #else + if( !fstat(my_fileno(fp), &st) ) return st.st_size; - } log_error("fstat() failed: %s\n", strerror(errno) ); + #endif break; } @@ -1364,27 +1877,55 @@ iobuf_get_filelength( IOBUF a ) /**************** * Tell the file position, where the next read will take place */ -ulong +off_t iobuf_tell( IOBUF a ) { return a->ntotal + a->nbytes; } +#if !defined(HAVE_FSEEKO) && !defined(fseeko) + +#ifdef HAVE_LIMITS_H +# include <limits.h> +#endif +#ifndef LONG_MAX +# define LONG_MAX ((long) ((unsigned long) -1 >> 1)) +#endif +#ifndef LONG_MIN +# define LONG_MIN (-1 - LONG_MAX) +#endif + +/**************** + * A substitute for fseeko, for hosts that don't have it. + */ +static int +fseeko( FILE *stream, off_t newpos, int whence ) +{ + while( newpos != (long) newpos ) { + long pos = newpos < 0 ? LONG_MIN : LONG_MAX; + if( fseek( stream, pos, whence ) != 0 ) + return -1; + newpos -= pos; + whence = SEEK_CUR; + } + return fseek( stream, (long)newpos, whence ); +} +#endif /**************** * This is a very limited implementation. It simply discards all internal * buffering and removes all filters but the first one. */ int -iobuf_seek( IOBUF a, ulong newpos ) +iobuf_seek( IOBUF a, off_t newpos ) { file_filter_ctx_t *b = NULL; if( a->directfp ) { FILE *fp = a->directfp; - if( fseek( fp, newpos, SEEK_SET ) ) { - log_error("can't seek to %lu: %s\n", newpos, strerror(errno) ); + if( fseeko( fp, newpos, SEEK_SET ) ) { + log_error("can't seek: %s\n", strerror(errno) ); return -1; } clearerr(fp); @@ -1398,10 +1939,25 @@ iobuf_seek( IOBUF a, ulong newpos ) } if( !a ) return -1; - if( fseek( b->fp, newpos, SEEK_SET ) ) { - log_error("can't seek to %lu: %s\n", newpos, strerror(errno) ); - return -1; - } +#ifdef FILE_FILTER_USES_STDIO + if( fseeko( b->fp, newpos, SEEK_SET ) ) { + log_error("can't fseek: %s\n", strerror(errno) ); + return -1; + } +#else + #ifdef HAVE_DOSISH_SYSTEM + if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff ) { + log_error ("SetFilePointer failed on handle %p: ec=%d\n", + b->fp, (int)GetLastError () ); + return -1; + } + #else + if ( lseek (b->fp, newpos, SEEK_SET) == (off_t)-1 ) { + log_error("can't lseek: %s\n", strerror(errno) ); + return -1; + } + #endif +#endif } a->d.len = 0; /* discard buffer */ a->d.start = 0; @@ -1467,7 +2023,7 @@ iobuf_get_fname( IOBUF a ) void iobuf_set_block_mode( IOBUF a, size_t n ) { - block_filter_ctx_t *ctx = gcry_xcalloc( 1, sizeof *ctx ); + block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx ); assert( a->use == 1 || a->use == 2 ); ctx->use = a->use; @@ -1489,7 +2045,7 @@ iobuf_set_block_mode( IOBUF a, size_t n ) void iobuf_set_partial_block_mode( IOBUF a, size_t len ) { - block_filter_ctx_t *ctx = gcry_xcalloc( 1, sizeof *ctx ); + block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx ); assert( a->use == 1 || a->use == 2 ); ctx->use = a->use; @@ -1544,7 +2100,7 @@ iobuf_read_line( IOBUF a, byte **addr_of_buffer, if( !buffer ) { /* must allocate a new buffer */ length = 256; - buffer = gcry_xmalloc( length ); + buffer = m_alloc( length ); *addr_of_buffer = buffer; *length_of_buffer = length; } @@ -1564,7 +2120,7 @@ iobuf_read_line( IOBUF a, byte **addr_of_buffer, } length += 3; /* correct for the reserved byte */ length += length < 1024? 256 : 1024; - buffer = gcry_xrealloc( buffer, length ); + buffer = m_realloc( buffer, length ); *addr_of_buffer = buffer; *length_of_buffer = length; length -= 3; /* and reserve again */ @@ -1580,3 +2136,58 @@ iobuf_read_line( IOBUF a, byte **addr_of_buffer, return nbytes; } +/* This is the non iobuf specific function */ +int +iobuf_translate_file_handle ( int fd, int for_write ) +{ + #ifdef __MINGW32__ + { + int x; + + if ( fd <= 2 ) + return fd; /* do not do this for error, stdin, stdout, stderr */ + + x = _open_osfhandle ( fd, for_write? 1:0 ); + if (x==-1 ) + log_error ("failed to translate osfhandle %p\n", (void*)fd ); + else { + /*log_info ("_open_osfhandle %p yields %d%s\n", + (void*)fd, x, for_write? " for writing":"" );*/ + fd = x; + } + } + #endif + return fd; +} + +static int +translate_file_handle ( int fd, int for_write ) +{ + #ifdef __MINGW32__ + #ifdef FILE_FILTER_USES_STDIO + fd = iobuf_translate_file_handle (fd, for_write); + #else + { + int x; + + if ( fd == 0 ) + x = (int)GetStdHandle (STD_INPUT_HANDLE); + else if (fd == 1) + x = (int)GetStdHandle (STD_OUTPUT_HANDLE); + else if (fd == 2) + x = (int)GetStdHandle (STD_ERROR_HANDLE); + else + x = fd; + + if (x == -1) + log_debug ("GetStdHandle(%d) failed: ec=%d\n", + fd, (int)GetLastError () ); + + fd = x; + } + #endif + #endif + return fd; +} + + diff --git a/util/logger.c b/util/logger.c index ccf049f0c..a51455798 100644 --- a/util/logger.c +++ b/util/logger.c @@ -1,5 +1,5 @@ /* logger.c - log functions - * Copyright (C) 1998, 2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,7 +24,6 @@ #include <stdarg.h> #include <string.h> #include <errno.h> -#include <gcrypt.h> #include "util.h" #include "i18n.h" @@ -41,19 +40,17 @@ static FILE *logfp; void log_set_logfile( const char *name, int fd ) { + if( name ) + BUG(); + if( logfp && logfp != stderr && logfp != stdout ) - fclose( logfp ); - if( name ) { - logfp = fopen ( name, "a" ); - } - else { - if( fd == 1 ) - logfp = stdout; - else if( fd == 2 ) - logfp = stderr; - else - logfp = fdopen( fd, "a" ); - } + fclose( logfp ); + if( fd == 1 ) + logfp = stdout; + else if( fd == 2 ) + logfp = stderr; + else + logfp = fdopen( fd, "a" ); if( !logfp ) { logfp = stderr; log_fatal("can't open fd %d for logging: %s\n", fd, strerror(errno)); @@ -72,9 +69,9 @@ log_stream() void log_set_name( const char *name ) { - gcry_free(pgm_name); + m_free(pgm_name); if( name ) - pgm_name = gcry_xstrdup(name); + pgm_name = m_strdup(name); else pgm_name = NULL; } @@ -112,7 +109,7 @@ log_inc_errorcount() void -gpg_log_print_prefix(const char *text) +g10_log_print_prefix(const char *text) { if( !logfp ) logfp = stderr; @@ -120,6 +117,9 @@ gpg_log_print_prefix(const char *text) fprintf(logfp, "%s%s: %s", pgm_name, pidstring, text ); else fprintf(logfp, "?%s: %s", pidstring, text ); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } static void @@ -131,21 +131,27 @@ print_prefix_f(const char *text, const char *fname) fprintf(logfp, "%s%s:%s: %s", pgm_name, pidstring, fname, text ); else fprintf(logfp, "?%s:%s: %s", pidstring, fname, text ); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_info( const char *fmt, ... ) +g10_log_info( const char *fmt, ... ) { va_list arg_ptr ; - gpg_log_print_prefix(""); + g10_log_print_prefix(""); va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_info_f( const char *fname, const char *fmt, ... ) +g10_log_info_f( const char *fname, const char *fmt, ... ) { va_list arg_ptr ; @@ -153,22 +159,28 @@ gpg_log_info_f( const char *fname, const char *fmt, ... ) va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_error( const char *fmt, ... ) +g10_log_error( const char *fmt, ... ) { va_list arg_ptr ; - gpg_log_print_prefix(""); + g10_log_print_prefix(""); va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); errorcount++; +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_error_f( const char *fname, const char *fmt, ... ) +g10_log_error_f( const char *fname, const char *fmt, ... ) { va_list arg_ptr ; @@ -177,23 +189,29 @@ gpg_log_error_f( const char *fname, const char *fmt, ... ) vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); errorcount++; +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_fatal( const char *fmt, ... ) +g10_log_fatal( const char *fmt, ... ) { va_list arg_ptr ; - gpg_log_print_prefix("fatal: "); + g10_log_print_prefix("fatal: "); va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); secmem_dump_stats(); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ exit(2); } void -gpg_log_fatal_f( const char *fname, const char *fmt, ... ) +g10_log_fatal_f( const char *fname, const char *fmt, ... ) { va_list arg_ptr ; @@ -202,16 +220,19 @@ gpg_log_fatal_f( const char *fname, const char *fmt, ... ) vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); secmem_dump_stats(); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ exit(2); } void -gpg_log_bug( const char *fmt, ... ) +g10_log_bug( const char *fmt, ... ) { va_list arg_ptr ; putc('\n', stderr ); - gpg_log_print_prefix("Ohhhh jeeee: "); + g10_log_print_prefix("Ohhhh jeeee: "); va_start( arg_ptr, fmt ) ; vfprintf(stderr,fmt,arg_ptr) ; va_end(arg_ptr); @@ -220,33 +241,37 @@ gpg_log_bug( const char *fmt, ... ) abort(); } -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) +#if defined (__riscos__) \ + || ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )) void -gpg_log_bug0( const char *file, int line, const char *func ) +g10_log_bug0( const char *file, int line, const char *func ) { log_bug(_("... this is a bug (%s:%d:%s)\n"), file, line, func ); } #else void -gpg_log_bug0( const char *file, int line ) +g10_log_bug0( const char *file, int line ) { log_bug(_("you found a bug ... (%s:%d)\n"), file, line); } #endif void -gpg_log_debug( const char *fmt, ... ) +g10_log_debug( const char *fmt, ... ) { va_list arg_ptr ; - gpg_log_print_prefix("DBG: "); + g10_log_print_prefix("DBG: "); va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_debug_f( const char *fname, const char *fmt, ... ) +g10_log_debug_f( const char *fname, const char *fmt, ... ) { va_list arg_ptr ; @@ -254,19 +279,25 @@ gpg_log_debug_f( const char *fname, const char *fmt, ... ) va_start( arg_ptr, fmt ) ; vfprintf(logfp,fmt,arg_ptr) ; va_end(arg_ptr); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } void -gpg_log_hexdump( const char *text, const char *buf, size_t len ) +g10_log_hexdump( const char *text, const char *buf, size_t len ) { int i; - gpg_log_print_prefix(text); + g10_log_print_prefix(text); for(i=0; i < len; i++ ) fprintf(logfp, " %02X", ((const byte*)buf)[i] ); fputc('\n', logfp); +#ifdef __riscos__ + fflush( logfp ); +#endif /* __riscos__ */ } diff --git a/util/memory.c b/util/memory.c new file mode 100644 index 000000000..9fab9ea3b --- /dev/null +++ b/util/memory.c @@ -0,0 +1,634 @@ +/* memory.c - memory allocation + * Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 use our own memory allocation functions instead of plain malloc(), + * so that we can provide some special enhancements: + * a) functions to provide memory from a secure memory. + * b) by looking at the requested allocation size we + * can reuse memory very quickly (e.g. MPI storage) + * (really needed?) + * c) memory usage reporting if compiled with M_DEBUG + * d) memory checking if compiled with M_GUARD + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "types.h" +#include "memory.h" +#include "util.h" + + +#define MAGIC_NOR_BYTE 0x55 +#define MAGIC_SEC_BYTE 0xcc +#define MAGIC_END_BYTE 0xaa + +/* This is a very crude alignment check which does not work on all CPUs + * IIRC, I once introduced it for testing on an Alpha. We should better + * replace this guard stuff with one provided by a modern malloc library + */ +#if SIZEOF_UNSIGNED_LONG == 8 + #define EXTRA_ALIGN 4 +#else + #define EXTRA_ALIGN 0 +#endif + +#if defined(M_DEBUG) || defined(M_GUARD) + static void membug( const char *fmt, ... ); +#endif + +#ifdef M_DEBUG + + #ifndef M_GUARD + #define M_GUARD 1 + #endif + #undef m_alloc + #undef m_alloc_clear + #undef m_alloc_secure + #undef m_alloc_secure_clear + #undef m_realloc + #undef m_free + #undef m_check + #undef m_strdup + #define FNAME(a) m_debug_ ##a + #define FNAMEPRT , const char *info + #define FNAMEARG , info + #ifndef __riscos__ + #define store_len(p,n,m) do { add_entry(p,n,m, \ + info, __FUNCTION__); } while(0) + #else + #define store_len(p,n,m) do { add_entry(p,n,m, \ + info, __func__ ); } while(0) + #endif +#else + #define FNAME(a) m_ ##a + #define FNAMEPRT + #define FNAMEARG + #define store_len(p,n,m) do { ((byte*)p)[EXTRA_ALIGN+0] = n; \ + ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ; \ + ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ; \ + ((byte*)p)[EXTRA_ALIGN+3] = m? MAGIC_SEC_BYTE \ + : MAGIC_NOR_BYTE; \ + } while(0) +#endif + + +#ifdef M_GUARD +static long used_memory; +#endif + +#ifdef M_DEBUG /* stuff used for memory debuging */ + +struct info_entry { + struct info_entry *next; + unsigned count; /* call count */ + const char *info; /* the reference to the info string */ +}; + +struct memtbl_entry { + const void *user_p; /* for reference: the pointer given to the user */ + size_t user_n; /* length requested by the user */ + struct memtbl_entry *next; /* to build a list of unused entries */ + const struct info_entry *info; /* points into the table with */ + /* the info strings */ + unsigned inuse:1; /* this entry is in use */ + unsigned count:31; +}; + + +#define INFO_BUCKETS 53 +#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS ) +static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */ + +static struct memtbl_entry *memtbl; /* the table with the memory info */ +static unsigned memtbl_size; /* number of allocated entries */ +static unsigned memtbl_len; /* number of used entries */ +static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */ + +static void dump_table_at_exit(void); +static void dump_table(void); +static void check_allmem( const char *info ); + +/**************** + * Put the new P into the debug table and return a pointer to the table entry. + * mode is true for security. BY is the name of the function which called us. + */ +static void +add_entry( byte *p, unsigned n, int mode, const char *info, const char *by ) +{ + unsigned index; + struct memtbl_entry *e; + struct info_entry *ie; + + if( memtbl_len < memtbl_size ) + index = memtbl_len++; + else { + struct memtbl_entry *e; + /* look for a used entry in the table. We take the first one, + * so that freed entries remain as long as possible in the table + * (free appends a new one) + */ + if( (e = memtbl_unused) ) { + index = e - memtbl; + memtbl_unused = e->next; + e->next = NULL; + } + else { /* no free entries in the table: extend the table */ + if( !memtbl_size ) { /* first time */ + memtbl_size = 100; + if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) ) + membug("memory debug table malloc failed\n"); + index = 0; + memtbl_len = 1; + atexit( dump_table_at_exit ); + } + else { /* realloc */ + unsigned n = memtbl_size / 4; /* enlarge by 25% */ + if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl))) + membug("memory debug table realloc failed\n"); + memset(memtbl+memtbl_size, 0, n*sizeof *memtbl ); + memtbl_size += n; + index = memtbl_len++; + } + } + } + e = memtbl+index; + if( e->inuse ) + membug("Ooops: entry %u is flagged as in use\n", index); + e->user_p = p + EXTRA_ALIGN + 4; + e->user_n = n; + e->count++; + if( e->next ) + membug("Ooops: entry is in free entry list\n"); + /* do we already have this info string */ + for( ie = info_strings[info_hash(info)]; ie; ie = ie->next ) + if( ie->info == info ) + break; + if( !ie ) { /* no: make a new entry */ + if( !(ie = malloc( sizeof *ie )) ) + membug("can't allocate info entry\n"); + ie->next = info_strings[info_hash(info)]; + info_strings[info_hash(info)] = ie; + ie->info = info; + ie->count = 0; + } + ie->count++; + e->info = ie; + e->inuse = 1; + + /* put the index at the start of the memory */ + p[EXTRA_ALIGN+0] = index; + p[EXTRA_ALIGN+1] = index >> 8 ; + p[EXTRA_ALIGN+2] = index >> 16 ; + p[EXTRA_ALIGN+3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ; + if( DBG_MEMORY ) + log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by ); +} + + + +/**************** + * Check that the memory block is correct. The magic byte has already been + * checked. Checks which are done here: + * - see whether the index points into our memory table + * - see whether P is the same as the one stored in the table + * - see whether we have already freed this block. + */ +struct memtbl_entry * +check_mem( const byte *p, const char *info ) +{ + unsigned n; + struct memtbl_entry *e; + + n = p[EXTRA_ALIGN+0]; + n |= p[EXTRA_ALIGN+1] << 8; + n |= p[EXTRA_ALIGN+2] << 16; + + if( n >= memtbl_len ) + membug("memory at %p corrupted: index=%u table_len=%u (%s)\n", + p+EXTRA_ALIGN+4, n, memtbl_len, info ); + e = memtbl+n; + + if( e->user_p != p+EXTRA_ALIGN+4 ) + membug("memory at %p corrupted: reference mismatch (%s)\n", + p+EXTRA_ALIGN+4, info ); + if( !e->inuse ) + membug("memory at %p corrupted: marked as free (%s)\n", + p+EXTRA_ALIGN+4, info ); + + if( !(p[EXTRA_ALIGN+3] == MAGIC_NOR_BYTE + || p[EXTRA_ALIGN+3] == MAGIC_SEC_BYTE) ) + membug("memory at %p corrupted: underflow=%02x (%s)\n", + p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+3], info ); + if( p[EXTRA_ALIGN+4+e->user_n] != MAGIC_END_BYTE ) + membug("memory at %p corrupted: overflow=%02x (%s)\n", + p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+4+e->user_n], info ); + return e; +} + + +/**************** + * free the entry and the memory (replaces free) + */ +static void +free_entry( byte *p, const char *info ) +{ + struct memtbl_entry *e, *e2; + + check_allmem("add_entry"); + + e = check_mem(p, info); + if( DBG_MEMORY ) + log_debug( "%s frees %u bytes alloced by %s\n", + info, e->user_n, e->info->info ); + if( !e->inuse ) { + if( e->user_p == p + EXTRA_ALIGN+ 4 ) + membug("freeing an already freed pointer at %p\n", p+EXTRA_ALIGN+4 ); + else + membug("freeing pointer %p which is flagged as freed\n", p+EXTRA_ALIGN+4 ); + } + + e->inuse = 0; + e->next = NULL; + if( !memtbl_unused ) + memtbl_unused = e; + else { + for(e2=memtbl_unused; e2->next; e2 = e2->next ) + ; + e2->next = e; + } + if( m_is_secure(p+EXTRA_ALIGN+4) ) + secmem_free(p); + else { + memset(p,'f', e->user_n+5); + free(p); + } +} + +static void +dump_entry(struct memtbl_entry *e ) +{ + unsigned n = e - memtbl; + + fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n", + n, e->inuse?'a':'u', e->count, e->user_p, e->user_n, + e->info->info, e->info->count ); + + +} + + +static void +dump_table_at_exit( void) +{ + if( DBG_MEMSTAT ) + dump_table(); +} + +static void +dump_table( void) +{ + unsigned n; + struct memtbl_entry *e; + ulong sum = 0, chunks =0; + + for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { + if(e->inuse) { + dump_entry(e); + sum += e->user_n; + chunks++; + } + } + fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n", + sum, chunks ); +} + + +static void +check_allmem( const char *info ) +{ + unsigned n; + struct memtbl_entry *e; + + for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { + if( e->inuse ) { + #ifndef __riscos__ + check_mem(e->user_p-4-EXTRA_ALIGN, info); + #else + check_mem((const byte *) e->user_p-4-EXTRA_ALIGN, info); + #endif + } + } +} + +#endif /* M_DEBUG */ + +#if defined(M_DEBUG) || defined(M_GUARD) +static void +membug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "\nMemory Error: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + fflush(stderr); + #ifdef M_DEBUG + if( DBG_MEMSTAT ) + dump_table(); + #endif + abort(); +} +#endif + +void +m_print_stats( const char *prefix ) +{ + #ifdef M_DEBUG + unsigned n; + struct memtbl_entry *e; + ulong sum = 0, chunks =0; + + for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { + if(e->inuse) { + sum += e->user_n; + chunks++; + } + } + + log_debug( "%s%smemstat: %8lu bytes in %ld chunks used\n", + prefix? prefix:"", prefix? ": ":"", sum, chunks ); + #elif defined(M_GUARD) + log_debug( "%s%smemstat: %8ld bytes\n", + prefix? prefix:"", prefix? ": ":"", used_memory ); + #endif +} + +void +m_dump_table( const char *prefix ) +{ + #ifdef M_DEBUG + fprintf(stderr,"Memory-Table-Dump: %s\n", prefix); + dump_table(); + #endif + m_print_stats( prefix ); +} + + +static void +out_of_core(size_t n, int secure) +{ + log_error ("out of %s memory while allocating %u bytes\n", + secure? "secure":"" ,(unsigned)n ); + if (secure) { + /*secmem_dump_stats ();*/ + log_info ("(this may be caused by too many secret keys used " + "simultaneously or due to excessive large key sizes)\n"); + } + exit (2); +} + +/**************** + * Allocate memory of size n. + * This function gives up if we do not have enough memory + */ +void * +FNAME(alloc)( size_t n FNAMEPRT ) +{ + char *p; + + #ifdef M_GUARD + if(!n) + out_of_core(n,0); /* should never happen */ + if( !(p = malloc( n + EXTRA_ALIGN+5 )) ) + out_of_core(n,0); + store_len(p,n,0); + used_memory += n; + p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; + return p+EXTRA_ALIGN+4; + #else + /* mallocing zero bytes is undefined by ISO-C, so we better make + sure that it won't happen */ + if (!n) + n = 1; + if( !(p = malloc( n )) ) + out_of_core(n,0); + return p; + #endif +} + +/**************** + * Allocate memory of size n from the secure memory pool. + * This function gives up if we do not have enough memory + */ +void * +FNAME(alloc_secure)( size_t n FNAMEPRT ) +{ + char *p; + + #ifdef M_GUARD + if(!n) + out_of_core(n,1); /* should never happen */ + if( !(p = secmem_malloc( n +EXTRA_ALIGN+ 5 )) ) + out_of_core(n,1); + store_len(p,n,1); + p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; + return p+EXTRA_ALIGN+4; + #else + /* mallocing zero bytes is undefined by ISO-C, so we better make + sure that it won't happen */ + if (!n) + n = 1; + if( !(p = secmem_malloc( n )) ) + out_of_core(n,1); + return p; + #endif +} + +void * +FNAME(alloc_clear)( size_t n FNAMEPRT ) +{ + void *p; + p = FNAME(alloc)( n FNAMEARG ); + memset(p, 0, n ); + return p; +} + +void * +FNAME(alloc_secure_clear)( size_t n FNAMEPRT) +{ + void *p; + p = FNAME(alloc_secure)( n FNAMEARG ); + memset(p, 0, n ); + return p; +} + + +/**************** + * realloc and clear the old space + */ +void * +FNAME(realloc)( void *a, size_t n FNAMEPRT ) +{ + void *b; + + #ifdef M_GUARD + if( a ) { + unsigned char *p = a; + size_t len = m_size(a); + + if( len >= n ) /* we don't shrink for now */ + return a; + if( p[-1] == MAGIC_SEC_BYTE ) + b = FNAME(alloc_secure_clear)(n FNAMEARG); + else + b = FNAME(alloc_clear)(n FNAMEARG); + FNAME(check)(NULL FNAMEARG); + memcpy(b, a, len ); + FNAME(free)(p FNAMEARG); + } + else + b = FNAME(alloc)(n FNAMEARG); + #else + if( m_is_secure(a) ) { + if( !(b = secmem_realloc( a, n )) ) + out_of_core(n,1); + } + else { + if( !(b = realloc( a, n )) ) + out_of_core(n,0); + } + #endif + + return b; +} + + + +/**************** + * Free a pointer + */ +void +FNAME(free)( void *a FNAMEPRT ) +{ + byte *p = a; + + if( !p ) + return; + #ifdef M_DEBUG + free_entry(p-EXTRA_ALIGN-4, info); + #elif defined M_GUARD + m_check(p); + if( m_is_secure(a) ) + secmem_free(p-EXTRA_ALIGN-4); + else { + used_memory -= m_size(a); + free(p-EXTRA_ALIGN-4); + } + #else + if( m_is_secure(a) ) + secmem_free(p); + else + free(p); + #endif +} + + +void +FNAME(check)( const void *a FNAMEPRT ) +{ + #ifdef M_GUARD + const byte *p = a; + + #ifdef M_DEBUG + if( p ) + check_mem(p-EXTRA_ALIGN-4, info); + else + check_allmem(info); + #else + if( !p ) + return; + if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) ) + membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] ); + else if( p[m_size(p)] != MAGIC_END_BYTE ) + membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] ); + #endif + #endif +} + + +size_t +m_size( const void *a ) +{ + #ifndef M_GUARD + log_debug("dummy m_size called\n"); + return 0; + #else + const byte *p = a; + size_t n; + + #ifdef M_DEBUG + n = check_mem(p-EXTRA_ALIGN-4, "m_size")->user_n; + #else + n = ((byte*)p)[-4]; + n |= ((byte*)p)[-3] << 8; + n |= ((byte*)p)[-2] << 16; + #endif + return n; + #endif +} + + +#if 0 /* not used */ +/**************** + * Make a copy of the memory block at a + */ +void * +FNAME(copy)( const void *a FNAMEPRT ) +{ + void *b; + size_t n; + + if( !a ) + return NULL; + + n = m_size(a); Aiiiih woher nehmen + if( m_is_secure(a) ) + b = FNAME(alloc_secure)(n FNAMEARG); + else + b = FNAME(alloc)(n FNAMEARG); + memcpy(b, a, n ); + return b; +} +#endif + +char * +FNAME(strdup)( const char *a FNAMEPRT ) +{ + size_t n = strlen(a); + char *p = FNAME(alloc)(n+1 FNAMEARG); + strcpy(p, a); + return p; +} + diff --git a/util/miscutil.c b/util/miscutil.c index 9b4a8379f..e1735cd59 100644 --- a/util/miscutil.c +++ b/util/miscutil.c @@ -1,5 +1,5 @@ /* miscutil.c - miscellaneous utilities - * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -27,7 +27,6 @@ #ifdef HAVE_LANGINFO_H #include <langinfo.h> #endif -#include <gcrypt.h> #include "types.h" #include "util.h" #include "i18n.h" @@ -125,10 +124,15 @@ strtimestamp( u32 stamp ) static char buffer[11+5]; struct tm *tp; time_t atime = stamp; - - tp = gmtime( &atime ); - sprintf(buffer,"%04d-%02d-%02d", - 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); + + if (atime < 0) { + strcpy (buffer, "????" "-??" "-??"); + } + else { + tp = gmtime( &atime ); + sprintf(buffer,"%04d-%02d-%02d", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); + } return buffer; } @@ -145,6 +149,11 @@ asctimestamp( u32 stamp ) struct tm *tp; time_t atime = stamp; + if (atime < 0) { + strcpy (buffer, "????" "-??" "-??"); + return buffer; + } + tp = localtime( &atime ); #ifdef HAVE_STRFTIME #if defined(HAVE_NL_LANGINFO) @@ -173,7 +182,8 @@ void print_string( FILE *fp, const byte *p, size_t n, int delim ) { for( ; n; n--, p++ ) - if( iscntrl( *p ) || *p == delim ) { + if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim || + (delim && *p=='\\')) { putc('\\', fp); if( *p == '\n' ) putc('n', fp); @@ -198,7 +208,7 @@ print_string( FILE *fp, const byte *p, size_t n, int delim ) * Print an UTF8 string to FP and filter all control characters out. */ void -print_utf8_string( FILE *fp, const byte *p, size_t n ) +print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim ) { size_t i; char *buf; @@ -209,17 +219,24 @@ print_utf8_string( FILE *fp, const byte *p, size_t n ) break; } if( i < n ) { - buf = utf8_to_native( p, n ); + buf = utf8_to_native ( p, n, delim ); + /*(utf8 conversion already does the control character quoting)*/ fputs( buf, fp ); - gcry_free( buf ); + m_free( buf ); } else - print_string( fp, p, n, 0 ); + print_string( fp, p, n, delim ); +} + +void +print_utf8_string( FILE *fp, const byte *p, size_t n ) +{ + print_utf8_string2 (fp, p, n, 0); } /**************** * This function returns a string which is suitable for printing - * Caller must release it with gcry_free() + * Caller must release it with m_free() */ char * make_printable_string( const byte *p, size_t n, int delim ) @@ -230,7 +247,8 @@ make_printable_string( const byte *p, size_t n, int delim ) /* first count length */ for(save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) { - if( iscntrl( *p ) || *p == delim ) { + if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim || + (delim && *p=='\\')) { if( *p=='\n' || *p=='\r' || *p=='\f' || *p=='\v' || *p=='\b' || !*p ) buflen += 2; @@ -243,9 +261,10 @@ make_printable_string( const byte *p, size_t n, int delim ) p = save_p; n = save_n; /* and now make the string */ - d = buffer = gcry_xmalloc( buflen ); + d = buffer = m_alloc( buflen ); for( ; n; n--, p++ ) { - if( iscntrl( *p ) || *p == delim ) { + if( *p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim || + (delim && *p=='\\')) { *d++ = '\\'; if( *p == '\n' ) *d++ = 'n'; @@ -271,32 +290,37 @@ make_printable_string( const byte *p, size_t n, int delim ) return buffer; } - int -answer_is_yes( const char *s ) +answer_is_yes_no_default( const char *s, int def_answer ) { - char *long_yes = _("yes"); - char *short_yes = _("yY"); - char *long_no = _("no"); - char *short_no = _("nN"); + const char *long_yes = _("yes"); + const char *short_yes = _("yY"); + const char *long_no = _("no"); + const char *short_no = _("nN"); - if( !stricmp(s, long_yes ) ) + /* Note: we have to use the local dependent strcasecmp here */ + if( !strcasecmp(s, long_yes ) ) return 1; - if( strchr( short_yes, *s ) && !s[1] ) + if( *s && strchr( short_yes, *s ) && !s[1] ) return 1; /* test for no strings to catch ambiguities for the next test */ - if( !stricmp(s, long_no ) ) + if( !strcasecmp(s, long_no ) ) return 0; - if( strchr( short_no, *s ) && !s[1] ) + if( *s && strchr( short_no, *s ) && !s[1] ) return 0; /* test for the english version (for those who are used to type yes) */ - if( !stricmp(s, "yes" ) ) + if( !ascii_strcasecmp(s, "yes" ) ) return 1; - if( strchr( "yY", *s ) && !s[1] ) + if( *s && strchr( "yY", *s ) && !s[1] ) return 1; - return 0; + return def_answer; } +int +answer_is_yes( const char *s ) +{ + return answer_is_yes_no_default(s,0); +} /**************** * Return 1 for yes, -1 for quit, or 0 for no @@ -304,34 +328,34 @@ answer_is_yes( const char *s ) int answer_is_yes_no_quit( const char *s ) { - char *long_yes = _("yes"); - char *long_no = _("no"); - char *long_quit = _("quit"); - char *short_yes = _("yY"); - char *short_no = _("nN"); - char *short_quit = _("qQ"); + const char *long_yes = _("yes"); + const char *long_no = _("no"); + const char *long_quit = _("quit"); + const char *short_yes = _("yY"); + const char *short_no = _("nN"); + const char *short_quit = _("qQ"); - if( !stricmp(s, long_no ) ) + /* Note: We have to use the locale dependent strcasecmp */ + if( !strcasecmp(s, long_no ) ) return 0; - if( !stricmp(s, long_yes ) ) + if( !strcasecmp(s, long_yes ) ) return 1; - if( !stricmp(s, long_quit ) ) + if( !strcasecmp(s, long_quit ) ) return -1; - if( strchr( short_no, *s ) && !s[1] ) + if( *s && strchr( short_no, *s ) && !s[1] ) return 0; - if( strchr( short_yes, *s ) && !s[1] ) + if( *s && strchr( short_yes, *s ) && !s[1] ) return 1; - if( strchr( short_quit, *s ) && !s[1] ) + if( *s && strchr( short_quit, *s ) && !s[1] ) return -1; - if( !stricmp(s, "yes" ) ) + /* but not here */ + if( !ascii_strcasecmp(s, "yes" ) ) return 1; - if( !stricmp(s, "quit" ) ) + if( !ascii_strcasecmp(s, "quit" ) ) return -1; - if( strchr( "yY", *s ) && !s[1] ) + if( *s && strchr( "yY", *s ) && !s[1] ) return 1; - if( strchr( "qQ", *s ) && !s[1] ) + if( *s && strchr( "qQ", *s ) && !s[1] ) return -1; return 0; } - - diff --git a/util/riscos.c b/util/riscos.c new file mode 100644 index 000000000..e0844a205 --- /dev/null +++ b/util/riscos.c @@ -0,0 +1,327 @@ +/* riscos.c - RISC OS stuff + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG for RISC OS. + * + * GnuPG 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. + * + * GnuPG 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 __RISCOS__C__ +#define __RISCOS__C__ + +#include <config.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <kernel.h> +#include <swis.h> +#include "util.h" +#include "memory.h" + +#define __UNIXLIB_INTERNALS +#include <unixlib/unix.h> +#undef __UNIXLIB_INTERNALS + +/* RISC OS specific defines that are not yet in UnixLib */ + +#define MimeMap_Translate 0x50B00 +#define MMM_TYPE_RISCOS 0 +#define MMM_TYPE_RISCOS_STRING 1 +#define MMM_TYPE_MIME 2 +#define MMM_TYPE_DOT_EXTN 3 + +/* RISC OS file open descriptor control list */ + +struct fds_item { + int fd; + struct fds_item *next; +}; +static struct fds_item *fds_list = NULL; +static int initialized = 0; + + +/* local RISC OS functions */ + +static int +is_read_only(const char *filename) +{ + _kernel_swi_regs r; + + r.r[0] = 17; + r.r[1] = (int) filename; + + if (_kernel_swi(OS_File, &r, &r)) + log_fatal("Can't get file attributes for %s!\n", filename); + + if (r.r[0] == 0) + log_fatal("Can't find file %s!\n", filename); + + r.r[0] = 4; + if (_kernel_swi(OS_File, &r, &r)) + return 1; + + return 0; +} + +static void +riscos_set_filetype_by_number(const char *filename, int type) +{ + _kernel_swi_regs r; + + r.r[0] = 18; + r.r[1] = (int) filename; + r.r[2] = type; + + if (_kernel_swi(OS_File, &r, &r)) + log_fatal("Can't set filetype for file %s!\n" + "Is the file on a read-only file system?\n", filename); +} + +/* exported RISC OS functions */ + +void +riscos_global_defaults() +{ + __riscosify_control = __RISCOSIFY_NO_PROCESS; + __feature_imagefs_is_file = 1; +} + +void +riscos_set_filetype(const char *filename, const char *mimetype) +{ + _kernel_swi_regs r; + + r.r[0] = MMM_TYPE_MIME; + r.r[1] = (int) mimetype; + r.r[2] = MMM_TYPE_RISCOS; + + if (_kernel_swi(MimeMap_Translate, &r, &r)) + log_fatal("Can't translate MIME type %s!\n", mimetype); + + riscos_set_filetype_by_number(filename, r.r[3]); +} + +pid_t +riscos_getpid(void) +{ + _kernel_swi_regs r; + + r.r[0] = 3; + if (_kernel_swi(Wimp_ReadSysInfo, &r, &r)) + log_fatal("Wimp_ReadSysInfo failed: Can't get WimpState (R0=3)!\n"); + + if (!r.r[0]) + return (pid_t) 0; + + r.r[0] = 5; + if (_kernel_swi(Wimp_ReadSysInfo, &r, &r)) + log_fatal("Wimp_ReadSysInfo failed: Can't get task handle (R0=5)!\n"); + + return (pid_t) r.r[0]; +} + +int +riscos_kill(pid_t pid, int sig) +{ + _kernel_swi_regs r; + int buf[4]; + + if (sig) + kill(pid, sig); + + r.r[0] = 0; + do { + r.r[1] = (int) buf; + r.r[2] = 16; + if (_kernel_swi(TaskManager_EnumerateTasks, &r, &r)) + log_fatal("TaskManager_EnumerateTasks failed!\n"); + if (buf[0] == pid) + return 0; + } while (r.r[0] >= 0); + + return __set_errno(ESRCH); +} + +int +riscos_access(const char *path, int amode) +{ + /* Do additional check, i.e. whether path is on write-protected floppy */ + if ((amode & W_OK) && is_read_only(path)) + return 1; + return access(path, amode); +} + +#ifdef DEBUG +void +dump_fdlist(void) +{ + struct fds_item *iter = fds_list; + printf("List of open file descriptors:\n"); + while (iter) { + printf(" %i\n", iter->fd); + iter = iter->next; + } +} +#endif /* DEBUG */ + +int +fdopenfile(const char *filename, const int allow_write) +{ + struct fds_item *h; + int fd; + if (allow_write) + fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); + else + fd = open(filename, O_RDONLY); + if (fd == -1) + log_error("Can't open file %s: %i, %s!\n", filename, errno, strerror(errno)); + + if (!initialized) { + atexit (close_fds); + initialized = 1; + } + + h = fds_list; + fds_list = (struct fds_item *) m_alloc(sizeof(struct fds_item)); + fds_list->fd = fd; + fds_list->next = h; + + return fd; +} + +void +close_fds(void) +{ + FILE *fp; + struct fds_item *h = fds_list; + while( fds_list ) { + h = fds_list->next; + fp = fdopen (fds_list->fd, "a"); + if (fp) + fflush(fp); + close(fds_list->fd); + m_free(fds_list); + fds_list = h; + } +} + +int +renamefile(const char *old, const char *new) +{ + _kernel_swi_regs r; + _kernel_oserror *e; + + r.r[0] = 25; + r.r[1] = (int) old; + r.r[2] = (int) new; + if (e = _kernel_swi(OS_FSControl, &r, &r)) { + if (e->errnum == 214) + return __set_errno(ENOENT); + if (e->errnum == 176) + return __set_errno(EEXIST); + printf("Error during renaming: %i, %s!\n", e->errnum, e->errmess); + return __set_errno(EOPSYS); + } + return 0; +} + +char * +gstrans(const char *old) +{ + _kernel_swi_regs r; + int c = 0; + int size = 256; + char *buf, *tmp; + + buf = (char *) m_alloc(size); + if (!buf) + log_fatal("Can't claim memory for OS_GSTrans buffer!\n"); + do { + r.r[0] = (int) old; + r.r[1] = (int) buf; + r.r[2] = size; + _kernel_swi_c(OS_GSTrans, &r, &r, &c); + if (c) { + size += 256; + tmp = (char *) m_realloc(buf, size); + if (!tmp) + log_fatal("Can't claim memory for OS_GSTrans buffer!\n"); + buf = tmp; + } + } while (c); + + buf[r.r[2]] = '\0'; + tmp = (char *) m_realloc(buf, r.r[2] + 1); + if (!tmp) + log_fatal("Can't realloc memory after OS_GSTrans!\n"); + + return tmp; +} + +#ifdef DEBUG +void +list_openfiles(void) +{ + _kernel_swi_regs r; + char *name; + int i; + + for (i = 255; i >= 0; --i) { + r.r[0] = 7; + r.r[1] = i; + r.r[2] = 0; + r.r[5] = 0; + if (_kernel_swi(OS_Args, &r, &r)) + continue; + + name = (char *) m_alloc(1-r.r[5]); + if (!name) + log_fatal("Can't claim memory for OS_Args buffer!\n"); + + r.r[0] = 7; + r.r[1] = i; + r.r[2] = (int) name; + r.r[5] = 1-r.r[5]; + if (_kernel_swi(OS_Args, &r, &r)) { + m_free(name); + log_fatal("Error when calling OS_Args(7)!\n"); + } + + r.r[0] = 254; + r.r[1] = i; + if (_kernel_swi(OS_Args, &r, &r)) { + m_free(name); + log_fatal("Error when calling OS_Args(254)!\n"); + } + + printf("%3i: %s (%c%c)\n", i, name, + (r.r[0] & 0x40) ? 'R' : 0, + (r.r[0] & 0x80) ? 'W' : 0); + m_free(name); + } +} +#endif + +void +not_implemented(const char *feature) +{ + log_info("%s is not implemented in the RISC OS version!\n", feature); +} + +#endif /* !__RISCOS__C__ */ diff --git a/util/secmem.c b/util/secmem.c new file mode 100644 index 000000000..c808dfeea --- /dev/null +++ b/util/secmem.c @@ -0,0 +1,468 @@ +/* secmem.c - memory allocation from a secure heap + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <unistd.h> +#if defined(HAVE_MLOCK) || defined(HAVE_MMAP) + #include <sys/mman.h> + #include <sys/types.h> + #include <fcntl.h> + #ifdef USE_CAPABILITIES + #include <sys/capability.h> + #endif + #ifdef HAVE_PLOCK + #include <sys/lock.h> + #endif +#endif + +#include "types.h" +#include "memory.h" +#include "util.h" +#include "i18n.h" + +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON +#endif +/* It seems that Slackware 7.1 does not know about EPERM */ +#if !defined(EPERM) && defined(ENOMEM) + #define EPERM ENOMEM +#endif + + +#define DEFAULT_POOLSIZE 16384 + +typedef struct memblock_struct MEMBLOCK; +struct memblock_struct { + unsigned size; + union { + MEMBLOCK *next; + PROPERLY_ALIGNED_TYPE aligned; + } u; +}; + + + +static void *pool; +static volatile int pool_okay; /* may be checked in an atexit function */ +static volatile int pool_is_mmapped; +static size_t poolsize; /* allocated length */ +static size_t poollen; /* used length */ +static MEMBLOCK *unused_blocks; +static unsigned max_alloced; +static unsigned cur_alloced; +static unsigned max_blocks; +static unsigned cur_blocks; +static int disable_secmem; +static int show_warning; +static int no_warning; +static int suspend_warning; + + +static void +print_warn(void) +{ + if (!no_warning) + { + log_info(_("Warning: using insecure memory!\n")); + log_info(_("please see http://www.gnupg.org/faq.html " + "for more information\n")); + } +} + + +static void +lock_pool( void *p, size_t n ) +{ + #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK) + int err; + + cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); + err = mlock( p, n ); + if( err && errno ) + err = errno; + cap_set_proc( cap_from_text("cap_ipc_lock+p") ); + + if( err ) { + if( errno != EPERM + #ifdef EAGAIN /* OpenBSD returns this */ + && errno != EAGAIN + #endif + #ifdef ENOSYS /* Some SCOs return this (function not implemented) */ + && errno != ENOSYS + #endif + #ifdef ENOMEM /* Linux can return this */ + && errno != ENOMEM + #endif + ) + log_error("can't lock memory: %s\n", strerror(err)); + show_warning = 1; + } + + #elif defined(HAVE_MLOCK) + uid_t uid; + int err; + + uid = getuid(); + + #ifdef HAVE_BROKEN_MLOCK + /* ick. but at least we get secured memory. about to lock + entire data segment. */ + #ifdef HAVE_PLOCK + err = plock( DATLOCK ); + if( err && errno ) + err = errno; +#else /*!HAVE_PLOCK*/ + if( uid ) { + errno = EPERM; + err = errno; + } + else { + err = mlock( p, n ); + if( err && errno ) + err = errno; + } + #endif /*!HAVE_PLOCK*/ + #else + err = mlock( p, n ); + if( err && errno ) + err = errno; + #endif + + if( uid && !geteuid() ) { + /* check that we really dropped the privs. + * Note: setuid(0) should always fail */ + if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) + log_fatal("failed to reset uid: %s\n", strerror(errno)); + } + + if( err ) { + if( errno != EPERM + #ifdef EAGAIN /* OpenBSD returns this */ + && errno != EAGAIN + #endif + #ifdef ENOSYS /* Some SCOs return this (function not implemented) */ + && errno != ENOSYS + #endif + #ifdef ENOMEM /* Linux can return this */ + && errno != ENOMEM + #endif + ) + log_error("can't lock memory: %s\n", strerror(err)); + show_warning = 1; + } + + #elif defined ( __QNX__ ) + /* QNX does not page at all, so the whole secure memory stuff does + * not make much sense. However it is still of use because it + * wipes out the memory on a free(). + * Therefore it is sufficient to suppress the warning + */ + #elif defined (HAVE_DOSISH_SYSTEM) + /* It does not make sense to print such a warning, given the fact that + * this whole Windows !@#$% and their user base are inherently insecure + */ + #elif defined (__riscos__) + /* no virtual memory on RISC OS, so no pages are swapped to disc, + * besides we don't have mmap, so we don't use it! ;-) + * But don't complain, as explained above. + */ + #else + log_info("Please note that you don't have secure memory on this system\n"); + #endif +} + + +static void +init_pool( size_t n) +{ + size_t pgsize; + + poolsize = n; + + if( disable_secmem ) + log_bug("secure memory is disabled"); + + #ifdef HAVE_GETPAGESIZE + pgsize = getpagesize(); + #else + pgsize = 4096; + #endif + + #if HAVE_MMAP + poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1); + #ifdef MAP_ANONYMOUS + pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + #else /* map /dev/zero instead */ + { int fd; + + fd = open("/dev/zero", O_RDWR); + if( fd == -1 ) { + log_error("can't open /dev/zero: %s\n", strerror(errno) ); + pool = (void*)-1; + } + else { + pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fd, 0); + } + } + #endif + if( pool == (void*)-1 ) + log_info("can't mmap pool of %u bytes: %s - using malloc\n", + (unsigned)poolsize, strerror(errno)); + else { + pool_is_mmapped = 1; + pool_okay = 1; + } + + #endif + if( !pool_okay ) { + pool = malloc( poolsize ); + if( !pool ) + log_fatal("can't allocate memory pool of %u bytes\n", + (unsigned)poolsize); + else + pool_okay = 1; + } + lock_pool( pool, poolsize ); + poollen = 0; +} + + +/* concatenate unused blocks */ +static void +compress_pool(void) +{ + /* fixme: we really should do this */ +} + +void +secmem_set_flags( unsigned flags ) +{ + int was_susp = suspend_warning; + + no_warning = flags & 1; + suspend_warning = flags & 2; + + /* and now issue the warning if it is not longer suspended */ + if( was_susp && !suspend_warning && show_warning ) { + show_warning = 0; + print_warn(); + } +} + +unsigned +secmem_get_flags(void) +{ + unsigned flags; + + flags = no_warning ? 1:0; + flags |= suspend_warning ? 2:0; + return flags; +} + +void +secmem_init( size_t n ) +{ + if( !n ) { +#ifndef __riscos__ + #ifdef USE_CAPABILITIES + /* drop all capabilities */ + cap_set_proc( cap_from_text("all-eip") ); + + #elif !defined(HAVE_DOSISH_SYSTEM) + uid_t uid; + + disable_secmem=1; + uid = getuid(); + if( uid != geteuid() ) { + if( setuid( uid ) || getuid() != geteuid() || !setuid(0) ) + log_fatal("failed to drop setuid\n" ); + } + #endif +#endif /* !__riscos__ */ + } + else { + if( n < DEFAULT_POOLSIZE ) + n = DEFAULT_POOLSIZE; + if( !pool_okay ) + init_pool(n); + else + log_error("Oops, secure memory pool already initialized\n"); + } +} + + +void * +secmem_malloc( size_t size ) +{ + MEMBLOCK *mb, *mb2; + int compressed=0; + + if( !pool_okay ) { + log_info( + _("operation is not possible without initialized secure memory\n")); + log_info(_("(you may have used the wrong program for this task)\n")); + exit(2); + } + if( show_warning && !suspend_warning ) { + show_warning = 0; + print_warn(); + } + + /* blocks are always a multiple of 32 */ + size += sizeof(MEMBLOCK); + size = ((size + 31) / 32) * 32; + + retry: + /* try to get it from the used blocks */ + for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next ) + if( mb->size >= size ) { + if( mb2 ) + mb2->u.next = mb->u.next; + else + unused_blocks = mb->u.next; + goto leave; + } + /* allocate a new block */ + if( (poollen + size <= poolsize) ) { + mb = (void*)((char*)pool + poollen); + poollen += size; + mb->size = size; + } + else if( !compressed ) { + compressed=1; + compress_pool(); + goto retry; + } + else + return NULL; + + leave: + cur_alloced += mb->size; + cur_blocks++; + if( cur_alloced > max_alloced ) + max_alloced = cur_alloced; + if( cur_blocks > max_blocks ) + max_blocks = cur_blocks; + + return &mb->u.aligned.c; +} + + +void * +secmem_realloc( void *p, size_t newsize ) +{ + MEMBLOCK *mb; + size_t size; + void *a; + + mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); + size = mb->size; + if( newsize < size ) + return p; /* it is easier not to shrink the memory */ + a = secmem_malloc( newsize ); + if ( a ) { + memcpy(a, p, size); + memset((char*)a+size, 0, newsize-size); + secmem_free(p); + } + return a; +} + + +void +secmem_free( void *a ) +{ + MEMBLOCK *mb; + size_t size; + + if( !a ) + return; + + mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); + size = mb->size; + /* This does not make much sense: probably this memory is held in the + * cache. We do it anyway: */ + memset(mb, 0xff, size ); + memset(mb, 0xaa, size ); + memset(mb, 0x55, size ); + memset(mb, 0x00, size ); + mb->size = size; + mb->u.next = unused_blocks; + unused_blocks = mb; + cur_blocks--; + cur_alloced -= size; +} + +int +m_is_secure( const void *p ) +{ + return p >= pool && p < (void*)((char*)pool+poolsize); +} + + + +/**************** + * Warning: This code might be called by an interrupt handler + * and frankly, there should really be such a handler, + * to make sure that the memory is wiped out. + * We hope that the OS wipes out mlocked memory after + * receiving a SIGKILL - it really should do so, otherwise + * there is no chance to get the secure memory cleaned. + */ +void +secmem_term() +{ + if( !pool_okay ) + return; + + memset( pool, 0xff, poolsize); + memset( pool, 0xaa, poolsize); + memset( pool, 0x55, poolsize); + memset( pool, 0x00, poolsize); + #if HAVE_MMAP + if( pool_is_mmapped ) + munmap( pool, poolsize ); + #endif + pool = NULL; + pool_okay = 0; + poolsize=0; + poollen=0; + unused_blocks=NULL; +} + + +void +secmem_dump_stats() +{ + if( disable_secmem ) + return; + fprintf(stderr, + "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n", + cur_alloced, max_alloced, cur_blocks, max_blocks, + (ulong)poollen, (ulong)poolsize ); +} + diff --git a/util/simple-gettext.c b/util/simple-gettext.c index 80dbbfe0e..db229437d 100644 --- a/util/simple-gettext.c +++ b/util/simple-gettext.c @@ -1,5 +1,5 @@ /* simple-gettext.c - a simplified version of gettext. - * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -19,7 +19,7 @@ */ /* This is a simplified version of gettext written by Ulrich Drepper. - * It is used for the Win32 version of GnuPG becuase all the overhead + * It is used for the Win32 version of GnuPG beucase all the overhead * of gettext is not needed and we have to do some special Win32 stuff. * I decided that this is far easier than to tweak gettext for the special * cases (I tried it but it is a lot of code). wk 15.09.99 @@ -27,8 +27,8 @@ #include <config.h> #ifdef USE_SIMPLE_GETTEXT -#ifndef __MINGW32__ - #error This file can only be used with MinGW32 +#if !defined (__MINGW32__) && !defined (__CYGWIN32__) + #error This file can only be used with MingW32 or Cygwin32 #endif #include <stdio.h> @@ -244,7 +244,7 @@ set_gettext_file( const char *filename ) /* absolute path - use it as is */ domain = load_domain( filename ); } - else { /* relative path - append ".mo" and get DIR from the Registry */ + else { /* relative path - append ".mo" and get dir from the environment */ char *buf = NULL; char *dir; diff --git a/util/strgutil.c b/util/strgutil.c index 89722f8e4..ff1ff5126 100644 --- a/util/strgutil.c +++ b/util/strgutil.c @@ -1,5 +1,5 @@ /* strgutil.c - string utilities - * Copyright (C) 1998, 2000 Free Software Foundation, Inc. + * Copyright (C) 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -22,7 +22,6 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> -#include <gcrypt.h> #include "types.h" #include "util.h" #include "memory.h" @@ -66,29 +65,10 @@ static ushort latin2_unicode[128] = { 0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9 }; -static ushort ibm850_unicode[128] = { - 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, - 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, - 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, - 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192, - 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, - 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, - 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, - 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, - 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, - 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, - 0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce, - 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, - 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe, - 0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4, - 0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, - 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0, -}; -static int query_native_charset_done = 0; static const char *active_charset_name = "iso-8859-1"; static ushort *active_charset = NULL; - +static int no_translation = 0; void free_strlist( STRLIST sl ) @@ -97,7 +77,7 @@ free_strlist( STRLIST sl ) for(; sl; sl = sl2 ) { sl2 = sl->next; - gcry_free(sl); + m_free(sl); } } @@ -107,7 +87,7 @@ add_to_strlist( STRLIST *list, const char *string ) { STRLIST sl; - sl = gcry_xmalloc( sizeof *sl + strlen(string)); + sl = m_alloc( sizeof *sl + strlen(string)); sl->flags = 0; strcpy(sl->d, string); sl->next = *list; @@ -129,7 +109,7 @@ add_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) else { char *p = native_to_utf8( string ); sl = add_to_strlist( list, p ); - gcry_free( p ); + m_free( p ); } return sl; } @@ -139,7 +119,7 @@ append_to_strlist( STRLIST *list, const char *string ) { STRLIST r, sl; - sl = gcry_xmalloc( sizeof *sl + strlen(string)); + sl = m_alloc( sizeof *sl + strlen(string)); sl->flags = 0; strcpy(sl->d, string); sl->next = NULL; @@ -163,7 +143,7 @@ append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ) else { char *p = native_to_utf8( string ); sl = append_to_strlist( list, p ); - gcry_free( p ); + m_free( p ); } return sl; } @@ -188,99 +168,230 @@ strlist_last( STRLIST node ) return node; } +char * +pop_strlist( STRLIST *list ) +{ + char *str=NULL; + STRLIST sl=*list; + if(sl) + { + str=m_alloc(strlen(sl->d)+1); + strcpy(str,sl->d); -int -string_count_chr( const char *string, int c ) -{ - int count; - for(count=0; *string; string++ ) - if( *string == c ) - count++; - return count; + *list=sl->next; + m_free(sl); + } + + return str; } +/**************** + * look for the substring SUB in buffer and return a pointer to that + * substring in BUF or NULL if not found. + * Comparison is case-insensitive. + */ +const char * +memistr( const char *buf, size_t buflen, const char *sub ) +{ + const byte *t, *s ; + size_t n; + + for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) + if( toupper(*t) == toupper(*s) ) { + for( buf=t++, buflen = n--, s++; + n && toupper(*t) == toupper(*s); t++, s++, n-- ) + ; + if( !*s ) + return buf; + t = buf; n = buflen; s = sub ; + } + + return NULL ; +} -static const char* -query_native_charset(void) +const char * +ascii_memistr( const char *buf, size_t buflen, const char *sub ) { - #ifdef __MINGW32__ - unsigned int cp; + const byte *t, *s ; + size_t n; + + for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) + if( ascii_toupper(*t) == ascii_toupper(*s) ) { + for( buf=t++, buflen = n--, s++; + n && ascii_toupper(*t) == ascii_toupper(*s); t++, s++, n-- ) + ; + if( !*s ) + return buf; + t = buf; n = buflen; s = sub ; + } + + return NULL ; +} - cp = GetConsoleOutputCP(); - if( cp != GetConsoleCP() ) { - /* The input cgarset is not equal to the output charset - * our system depends on it and therefore we will set - * same the same (this won't work on Windows 95) */ - if( !SetConsoleCP( cp ) ) - log_info("can't set Input-CP to Output-CP: %d\n", - (int)GetLastError() ); +/**************** + * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein + * '\0' angeh�ngt. Ist n = 0, so geschieht nichts, ist Destination + * gleich NULL, so wird via m_alloc Speicher besorgt, ist dann nicht + * gen�gend Speicher vorhanden, so bricht die funktion ab. + */ +char * +mem2str( char *dest , const void *src , size_t n ) +{ + char *d; + const char *s; + + if( n ) { + if( !dest ) + dest = m_alloc( n ) ; + d = dest; + s = src ; + for(n--; n && *s; n-- ) + *d++ = *s++; + *d = '\0' ; } - /* we could read the registry, but this seems to be too much work */ - switch( cp ) { - case 850: return "ibm850"; - case 437: return "ibm437"; - case 1252: return "iso-8859-1"; - default: - log_info("unknown MS-Windows CodePage %u " - "- trying to switch to Latin-1\n", cp ); - /* try to set latin-1 */ - if( !SetConsoleOutputCP( 1252 ) ) { - if( !SetConsoleCP( 1252 ) ) - return "iso-8859-1"; - else /* back off */ - SetConsoleOutputCP( cp ); + + return dest ; +} + + +/**************** + * remove leading and trailing white spaces + */ +char * +trim_spaces( char *str ) +{ + char *string, *p, *mark; + + string = str; + /* find first non space character */ + for( p=string; *p && isspace( *(byte*)p ) ; p++ ) + ; + /* move characters */ + for( (mark = NULL); (*string = *p); string++, p++ ) + if( isspace( *(byte*)p ) ) { + if( !mark ) + mark = string ; + } + else + mark = NULL ; + if( mark ) + *mark = '\0' ; /* remove trailing spaces */ + + return str ; +} + + + +unsigned int +trim_trailing_chars( byte *line, unsigned len, const char *trimchars ) +{ + byte *p, *mark; + unsigned n; + + for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { + if( strchr(trimchars, *p ) ) { + if( !mark ) + mark = p; } - log_info("no information about MS-Windows CodePage %u\n", cp ); - return NULL; + else + mark = NULL; } - #else - return NULL; /* unknown */ - #endif + + if( mark ) { + *mark = 0; + return mark - line; + } + return len; } +/**************** + * remove trailing white spaces and return the length of the buffer + */ +unsigned +trim_trailing_ws( byte *line, unsigned len ) +{ + return trim_trailing_chars( line, len, " \t\r\n" ); +} -const char* -get_native_charset() +unsigned int +check_trailing_chars( const byte *line, unsigned int len, + const char *trimchars ) { - if( !query_native_charset_done ) { - const char *s; + const byte *p, *mark; + unsigned int n; - query_native_charset_done = 1; - s = query_native_charset(); - if( s ) - set_native_charset(s); + for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { + if( strchr(trimchars, *p ) ) { + if( !mark ) + mark = p; + } + else + mark = NULL; } - return active_charset_name; + if( mark ) { + return mark - line; + } + return len; +} + +/**************** + * remove trailing white spaces and return the length of the buffer + */ +unsigned int +check_trailing_ws( const byte *line, unsigned int len ) +{ + return check_trailing_chars( line, len, " \t\r\n" ); +} + + + +int +string_count_chr( const char *string, int c ) +{ + int count; + for(count=0; *string; string++ ) + if( *string == c ) + count++; + return count; } int set_native_charset( const char *newset ) { - query_native_charset_done = 1; /* don't do this when we want to set one*/ - if( !stricmp( newset, "iso-8859-1" ) ) { + if( !ascii_strcasecmp( newset, "iso-8859-1" ) ) { active_charset_name = "iso-8859-1"; + no_translation = 0; active_charset = NULL; } - else if( !stricmp( newset, "iso-8859-2" ) ) { + else if( !ascii_strcasecmp( newset, "iso-8859-2" ) ) { active_charset_name = "iso-8859-2"; + no_translation = 0; active_charset = latin2_unicode; } - else if( !stricmp( newset, "koi8-r" ) ) { + else if( !ascii_strcasecmp( newset, "koi8-r" ) ) { active_charset_name = "koi8-r"; + no_translation = 0; active_charset = koi8_unicode; } - else if( !stricmp( newset, "ibm850" ) || !stricmp( newset, "ibm437" ) ) { - active_charset_name = "ibm850"; - active_charset = ibm850_unicode; + else if( !ascii_strcasecmp (newset, "utf8" ) + || !ascii_strcasecmp(newset, "utf-8") ) { + active_charset_name = "utf-8"; + no_translation = 1; + active_charset = NULL; } else - return GPGERR_GENERAL; + return G10ERR_GENERAL; return 0; } +const char* +get_native_charset() +{ + return active_charset_name; +} /**************** * Convert string, which is in native encoding to UTF8 and return the @@ -294,13 +405,16 @@ native_to_utf8( const char *string ) byte *p; size_t length=0; - if( active_charset ) { + if (no_translation) { + buffer = m_strdup (string); + } + else if( active_charset ) { for(s=string; *s; s++ ) { length++; if( *s & 0x80 ) length += 2; /* we may need 3 bytes */ } - buffer = gcry_xmalloc( length + 1 ); + buffer = m_alloc( length + 1 ); for(p=buffer, s=string; *s; s++ ) { if( *s & 0x80 ) { ushort val = active_charset[ *s & 0x7f ]; @@ -325,7 +439,7 @@ native_to_utf8( const char *string ) if( *s & 0x80 ) length++; } - buffer = gcry_xmalloc( length + 1 ); + buffer = m_alloc( length + 1 ); for(p=buffer, s=string; *s; s++ ) { if( *s & 0x80 ) { *p++ = 0xc0 | ((*s >> 6) & 3); @@ -341,15 +455,17 @@ native_to_utf8( const char *string ) /**************** - * Convert string, which is in UTF8 to native encoding. - * illegal encodings by some "\xnn" and quote all control characters - */ + * Convert string, which is in UTF8 to native encoding. illegal + * encodings by some "\xnn" and quote all control characters. A + * character with value DELIM will always be quoted, it must be a + * vanilla ASCII character. + */ char * -utf8_to_native( const char *string, size_t length ) +utf8_to_native( const char *string, size_t length, int delim ) { int nleft; int i; - byte encbuf[7]; + byte encbuf[8]; int encidx; const byte *s; size_t n; @@ -376,7 +492,8 @@ utf8_to_native( const char *string, size_t length ) } if( !nleft ) { if( !(*s & 0x80) ) { /* plain ascii */ - if( iscntrl( *s ) ) { + if( *s < 0x20 || *s == 0x7f || *s == delim || + (delim && *s=='\\')) { n++; if( p ) *p++ = '\\'; @@ -387,11 +504,13 @@ utf8_to_native( const char *string, size_t length ) case '\v': n++; if( p ) *p++ = 'v'; break; case '\b': n++; if( p ) *p++ = 'b'; break; case 0 : n++; if( p ) *p++ = '0'; break; - default: n += 3; - sprintf( p, "x%02x", *s ); - if ( p ) - p += 3; - break; + default: + n += 3; + if ( p ) { + sprintf( p, "x%02x", *s ); + p += 3; + } + break; } } else { @@ -402,27 +521,32 @@ utf8_to_native( const char *string, size_t length ) else if( (*s & 0xe0) == 0xc0 ) { /* 110x xxxx */ val = *s & 0x1f; nleft = 1; - encbuf[encidx=0] = *s; + encidx = 0; + encbuf[encidx++] = *s; } else if( (*s & 0xf0) == 0xe0 ) { /* 1110 xxxx */ val = *s & 0x0f; nleft = 2; - encbuf[encidx=0] = *s; + encidx = 0; + encbuf[encidx++] = *s; } else if( (*s & 0xf8) == 0xf0 ) { /* 1111 0xxx */ val = *s & 0x07; nleft = 3; - encbuf[encidx=0] = *s; + encidx = 0; + encbuf[encidx++] = *s; } else if( (*s & 0xfc) == 0xf8 ) { /* 1111 10xx */ val = *s & 0x03; nleft = 4; - encbuf[encidx=0] = *s; + encidx = 0; + encbuf[encidx++] = *s; } else if( (*s & 0xfe) == 0xfc ) { /* 1111 110x */ val = *s & 0x01; nleft = 5; - encbuf[encidx=0] = *s; + encidx = 0; + encbuf[encidx++] = *s; } else { /* invalid encoding: print as \xnn */ if( p ) { @@ -435,19 +559,32 @@ utf8_to_native( const char *string, size_t length ) } else if( *s < 0x80 || *s >= 0xc0 ) { /* invalid */ if( p ) { + for(i=0; i < encidx; i++ ) { + sprintf(p, "\\x%02x", encbuf[i] ); + p += 4; + } sprintf(p, "\\x%02x", *s ); p += 4; } - n += 4; + n += 4 + 4*encidx; nleft = 0; + encidx = 0; resync = 1; } else { - encbuf[++encidx] = *s; + encbuf[encidx++] = *s; val <<= 6; val |= *s & 0x3f; if( !--nleft ) { /* ready */ - if( active_charset ) { /* table lookup */ + if (no_translation) { + if( p ) { + for(i=0; i < encidx; i++ ) + *p++ = encbuf[i]; + } + n += encidx; + encidx = 0; + } + else if( active_charset ) { /* table lookup */ for(i=0; i < 128; i++ ) { if( active_charset[i] == val ) break; @@ -464,6 +601,7 @@ utf8_to_native( const char *string, size_t length ) } } n += encidx*4; + encidx = 0; } } else { /* native set */ @@ -479,15 +617,15 @@ utf8_to_native( const char *string, size_t length ) } } n += encidx*4; + encidx = 0; } } - } } } if( !buffer ) { /* allocate the buffer after the first pass */ - buffer = p = gcry_xmalloc( n + 1 ); + buffer = p = m_alloc( n + 1 ); } else { *p = 0; /* make a string */ @@ -496,8 +634,262 @@ utf8_to_native( const char *string, size_t length ) } } +/**************************************************** + ******** locale insensitive ctype functions ******** + ****************************************************/ +/* FIXME: replace them by a table lookup and macros */ +int +ascii_isupper (int c) +{ + return c >= 'A' && c <= 'Z'; +} + +int +ascii_islower (int c) +{ + return c >= 'a' && c <= 'z'; +} + +int +ascii_toupper (int c) +{ + if (c >= 'a' && c <= 'z') + c &= ~0x20; + return c; +} + +int +ascii_tolower (int c) +{ + if (c >= 'A' && c <= 'Z') + c |= 0x20; + return c; +} + + +int +ascii_strcasecmp( const char *a, const char *b ) +{ + if (a == b) + return 0; + + for (; *a && *b; a++, b++) { + if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b)) + break; + } + return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); +} + +int +ascii_memcasecmp( const char *a, const char *b, size_t n ) +{ + if (a == b) + return 0; + for ( ; n; n--, a++, b++ ) { + if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) ) + return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); + } + return 0; +} + +/********************************************* + ********** missing string functions ********* + *********************************************/ +#ifndef HAVE_STPCPY +char * +stpcpy(char *a,const char *b) +{ + while( *b ) + *a++ = *b++; + *a = 0; + return (char*)a; +} +#endif + + +#ifndef HAVE_STRSEP +/* code taken from glibc-2.2.1/sysdeps/generic/strsep.c */ +char * +strsep (char **stringp, const char *delim) +{ + char *begin, *end; + + begin = *stringp; + if (begin == NULL) + return NULL; + + /* A frequent case is when the delimiter string contains only one + character. Here we don't need to call the expensive `strpbrk' + function and instead work using `strchr'. */ + if (delim[0] == '\0' || delim[1] == '\0') + { + char ch = delim[0]; + + if (ch == '\0') + end = NULL; + else + { + if (*begin == ch) + end = begin; + else if (*begin == '\0') + end = NULL; + else + end = strchr (begin + 1, ch); + } + } + else + /* Find the end of the token. */ + end = strpbrk (begin, delim); + + if (end) + { + /* Terminate the token and set *STRINGP past NUL character. */ + *end++ = '\0'; + *stringp = end; + } + else + /* No more delimiters; this is the last token. */ + *stringp = NULL; + + return begin; +} +#endif /*HAVE_STRSEP*/ + + +#ifndef HAVE_STRLWR +char * +strlwr(char *s) +{ + char *p; + for(p=s; *p; p++ ) + *p = tolower(*p); + return s; +} +#endif + +#ifndef HAVE_STRCASECMP +int +strcasecmp( const char *a, const char *b ) +{ + for( ; *a && *b; a++, b++ ) { + if( *a != *b && toupper(*a) != toupper(*b) ) + break; + } + return *(const byte*)a - *(const byte*)b; +} +#endif + +#ifndef HAVE_STRNCASECMP +int +strncasecmp( const char *a, const char *b, size_t n ) +{ + for( ; n && *a && *b; a++, b++, n--) { + if( *a != *b && toupper(*a) != toupper(*b) ) + break; + } + if (!n) + return 0; + return *(const byte*)a - *(const byte*)b; +} +#endif + + +#ifdef __MINGW32__ +/* + * Like vsprintf but provides a pointer to malloc'd storage, which + * must be freed by the caller (m_free). Taken from libiberty as + * found in gcc-2.95.2 and a little bit modernized. + * FIXME: Write a new CRT for W32. + */ +int +vasprintf ( char **result, const char *format, va_list args) +{ + const char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap; + + /* this is not really portable but works under Windows */ + memcpy ( &ap, &args, sizeof (va_list)); + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + { + char *endp; + total_width += strtoul (p, &endp, 10); + p = endp; + } + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + { + char *endp; + total_width += strtoul (p, &endp, 10); + p = endp; + } + } + while (strchr ("hlL", *p)) + ++p; + /* Should be big enough for any format specifier except %s + and floats. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + (void) va_arg (ap, int); + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + (void) va_arg (ap, double); + /* Since an ieee double can have an exponent of 307, we'll + make the buffer wide enough to cover the gross case. */ + total_width += 307; + + case 's': + total_width += strlen (va_arg (ap, char *)); + break; + case 'p': + case 'n': + (void) va_arg (ap, char *); + break; + } + } + } + *result = m_alloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, args); + else + return 0; +} +#endif /*__MINGW32__*/ diff --git a/util/ttyio.c b/util/ttyio.c index 6aaff000c..0a5df6099 100644 --- a/util/ttyio.c +++ b/util/ttyio.c @@ -1,5 +1,5 @@ /* ttyio.c - tty i/O functions - * Copyright (C) 1998, 2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -26,6 +26,11 @@ #include <unistd.h> #ifdef HAVE_TCGETATTR #include <termios.h> + #ifdef __riscos__ + #include <kernel.h> + #include <swis.h> + #undef HAVE_TCGETATTR + #endif /* __riscos__ */ #else #ifdef HAVE_TERMIO_H /* simulate termios with termio */ @@ -45,13 +50,16 @@ #endif #include <errno.h> #include <ctype.h> -#include <gcrypt.h> #include "util.h" #include "memory.h" #include "ttyio.h" #define CONTROL_D ('D' - 'A' + 1) - +#ifdef __VMS + #define TERMDEVICE "/dev/tty" +#else + #define TERMDEVICE "/dev/tty" +#endif #ifdef __MINGW32__ /* use the odd Win32 functions */ static struct { @@ -72,10 +80,16 @@ static int batchmode; static int no_terminal; #ifdef HAVE_TCGETATTR -static struct termios termsave; -static int restore_termios; + #ifdef __riscos__ + struct termios termsave; + int restore_termios; + #else + static struct termios termsave; + static int restore_termios; + #endif #endif + #ifdef HAVE_TCGETATTR static void cleanup(void) @@ -121,7 +135,7 @@ init_ttyfp(void) #elif defined(__EMX__) ttyfp = stdout; /* Fixme: replace by the real functions: see wklib */ #else - ttyfp = batchmode? stderr : fopen("/dev/tty", "r+"); + ttyfp = batchmode? stderr : fopen(TERMDEVICE, "r+"); if( !ttyfp ) { log_error("cannot open /dev/tty: %s\n", strerror(errno) ); exit(2); @@ -163,39 +177,21 @@ tty_printf( const char *fmt, ... ) va_start( arg_ptr, fmt ) ; #ifdef __MINGW32__ - { static char *buf; - static size_t bufsize; - int n; + { + char *buf = NULL; + int n; DWORD nwritten; - #if 0 /* the dox say, that there is a snprintf, but I didn't found - * it, so we use a static buffer for now */ - do { - if( n == -1 || !buf ) { - gcry_free(buf); - bufsize += 200; - /* better check the new size; (we use M$ functions) */ - if( bufsize > 50000 ) - log_bug("vsnprintf probably failed\n"); - buf = gcry_xmalloc( bufsize ); - } - n = _vsnprintf(buf, bufsize-1, fmt, arg_ptr); - } while( n == -1 ); - #else - if( !buf ) { - bufsize += 1000; - buf = gcry_xmalloc( bufsize ); - } - n = vsprintf(buf, fmt, arg_ptr); - if( n == -1 ) - log_bug("vsprintf() failed\n"); - #endif - + n = vasprintf(&buf, fmt, arg_ptr); + if( !buf ) + log_bug("vasprintf() failed\n"); + if( !WriteConsoleA( con.out, buf, n, &nwritten, NULL ) ) log_fatal("WriteConsole failed: rc=%d", (int)GetLastError() ); if( n != nwritten ) - log_fatal("WriteConsole failed: %d != %ld\n", n, nwritten ); + log_fatal("WriteConsole failed: %d != %d\n", n, (int)nwritten ); last_prompt_len += n; + m_free (buf); } #else last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ; @@ -261,13 +257,13 @@ tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) break; } if( i < n ) { - buf = utf8_to_native( p, n ); + buf = utf8_to_native( p, n, 0 ); if( strlen( buf ) > max_n ) { buf[max_n] = 0; } /*(utf8 conversion already does the control character quoting)*/ tty_printf("%s", buf ); - gcry_free( buf ); + m_free( buf ); } else { if( n > max_n ) { @@ -277,7 +273,6 @@ tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) } } - void tty_print_utf8_string( byte *p, size_t n ) { @@ -285,13 +280,16 @@ tty_print_utf8_string( byte *p, size_t n ) } - - static char * do_get( const char *prompt, int hidden ) { char *buf; + #ifndef __riscos__ byte cbuf[1]; + #else + int carry; + _kernel_swi_regs r; + #endif int c, n, i; if( batchmode ) { @@ -308,8 +306,8 @@ do_get( const char *prompt, int hidden ) init_ttyfp(); last_prompt_len = 0; - tty_printf( prompt ); - buf = gcry_xmalloc(n=50); + tty_printf( "%s", prompt ); + buf = m_alloc(n=50); i = 0; #ifdef __MINGW32__ /* windoze version */ @@ -338,7 +336,7 @@ do_get( const char *prompt, int hidden ) continue; if( !(i < n-1) ) { n += 50; - buf = gcry_xrealloc( buf, n ); + buf = m_realloc( buf, n ); } buf[i++] = c; } @@ -346,6 +344,50 @@ do_get( const char *prompt, int hidden ) if( hidden ) SetConsoleMode(con.in, DEF_INPMODE ); + #elif defined(__riscos__) + do { + if (_kernel_swi_c(OS_ReadC, &r, &r, &carry)) + log_fatal("OS_ReadC failed: Couldn't read from keyboard!\n"); + c = r.r[0]; + if (carry != 0) + log_fatal("OS_ReadC failed: Return Code = %i!\n", c); + if (c == 0xa || c == 0xd) { /* Return || Enter */ + c = (int) '\n'; + } else if (c == 0x8 || c == 0x7f) { /* Backspace || Delete */ + if (i>0) { + i--; + if (!hidden) { + last_prompt_len--; + fputc(8, ttyfp); + fputc(32, ttyfp); + fputc(8, ttyfp); + fflush(ttyfp); + } + } else { + fputc(7, ttyfp); + fflush(ttyfp); + } + continue; + } else if (c == (int) '\t') { /* Tab */ + c = ' '; + } else if (c > 0xa0) { + ; /* we don't allow 0xa0, as this is a protected blank which may + * confuse the user */ + } else if (iscntrl(c)) { + continue; + } + if(!(i < n-1)) { + n += 50; + buf = m_realloc(buf, n); + } + buf[i++] = c; + if (!hidden) { + last_prompt_len++; + fputc(c, ttyfp); + fflush(ttyfp); + } + } while (c != '\n'); + i = (i>0) ? i-1 : 0; #else /* unix version */ if( hidden ) { #ifdef HAVE_TCGETATTR @@ -378,7 +420,7 @@ do_get( const char *prompt, int hidden ) continue; if( !(i < n-1) ) { n += 50; - buf = gcry_xrealloc( buf, n ); + buf = m_realloc( buf, n ); } buf[i++] = c; } @@ -450,7 +492,7 @@ tty_get_answer_is_yes( const char *prompt ) char *p = tty_get( prompt ); tty_kill_prompt(); yes = answer_is_yes(p); - gcry_free(p); + m_free(p); return yes; } diff --git a/util/w32reg.c b/util/w32reg.c index 362bcab8f..000ae07b7 100644 --- a/util/w32reg.c +++ b/util/w32reg.c @@ -19,7 +19,8 @@ */ #include <config.h> -#ifdef __MINGW32__ /* This module is only used in this environment */ +#if defined (__MINGW32__) || defined (__CYGWIN32__) + /* This module is only used in this environment */ #include <stdio.h> #include <stdlib.h> @@ -29,23 +30,13 @@ #include "util.h" #include "memory.h" - -/**************** - * Return a string from the Win32 Registry or NULL in case of - * error. Caller must release the return value. A NUKK for root - * is an alias fro HKEY_CURRENT_USER - * NOTE: The value is allocated with a plain malloc() - use free() and not - * the usual gcry_free()!!! - */ -char * -read_w32_registry_string( const char *root, const char *dir, const char *name ) +static HKEY +get_root_key(const char *root) { - HKEY root_key, key_handle; - DWORD n1, nbytes; - char *result = NULL; - + HKEY root_key; + if( !root ) - root_key = HKEY_CURRENT_USER; + root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if( !strcmp( root, "HKEY_CURRENT_USER" ) ) @@ -59,6 +50,27 @@ read_w32_registry_string( const char *root, const char *dir, const char *name ) else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) root_key = HKEY_CURRENT_CONFIG; else + return NULL; + + return root_key; +} + + +/**************** + * Return a string from the Win32 Registry or NULL in case of + * error. Caller must release the return value. A NUKK for root + * is an alias fro HKEY_CURRENT_USER + * NOTE: The value is allocated with a plain malloc() - use free() and not + * the usual m_free()!!! + */ +char * +read_w32_registry_string( const char *root, const char *dir, const char *name ) +{ + HKEY root_key, key_handle; + DWORD n1, nbytes; + char *result = NULL; + + if ( !(root_key = get_root_key(root) ) ) return NULL; if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) @@ -82,7 +94,35 @@ read_w32_registry_string( const char *root, const char *dir, const char *name ) } +int +write_w32_registry_string(const char *root, const char *dir, + const char *name, const char *value) +{ + HKEY root_key, reg_key; + + if ( !(root_key = get_root_key(root) ) ) + return -1; + if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, ®_key ) + != ERROR_SUCCESS ) + return -1; + + if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, + strlen( value ) ) != ERROR_SUCCESS ) { + if ( RegCreateKey( root_key, name, ®_key ) != ERROR_SUCCESS ) { + RegCloseKey(reg_key); + return -1; + } + if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, + strlen( value ) ) != ERROR_SUCCESS ) { + RegCloseKey(reg_key); + return -1; + } + } + RegCloseKey( reg_key ); + + return 0; +} -#endif /* __MINGW32__ */ +#endif /* __MINGW32__ || __CYGWIN32__ */ |