aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorDavid Shaw <[email protected]>2002-06-29 13:46:34 +0000
committerDavid Shaw <[email protected]>2002-06-29 13:46:34 +0000
commit3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37 (patch)
treedac7a3780fb4edf9ca89c93800230e88ab255434 /util
parentUpdate head to match stable 1.0 (diff)
downloadgnupg-3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37.tar.gz
gnupg-3f51f7db3de85574dc5d6efd8b54ef78c1cd3f37.zip
Update head to match stable 1.0
Diffstat (limited to 'util')
-rw-r--r--util/ChangeLog513
-rw-r--r--util/Makefile.am31
-rw-r--r--util/README7
-rw-r--r--util/argparse.c1000
-rw-r--r--util/dotlock.c420
-rw-r--r--util/errors.c20
-rw-r--r--util/fileutil.c103
-rw-r--r--util/g10u.c40
-rw-r--r--util/http.c231
-rw-r--r--util/iobuf.c947
-rw-r--r--util/logger.c103
-rw-r--r--util/memory.c634
-rw-r--r--util/miscutil.c116
-rw-r--r--util/riscos.c327
-rw-r--r--util/secmem.c468
-rw-r--r--util/simple-gettext.c10
-rw-r--r--util/strgutil.c606
-rw-r--r--util/ttyio.c128
-rw-r--r--util/w32reg.c74
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, &reg_key )
+ != ERROR_SUCCESS )
+ return -1;
+
+ if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value,
+ strlen( value ) ) != ERROR_SUCCESS ) {
+ if ( RegCreateKey( root_key, name, &reg_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__ */