2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-3.11-20250717

This commit is contained in:
Wietse Z Venema 2025-07-17 00:00:00 -05:00 committed by Viktor Dukhovni
parent 9b4d4d966e
commit 13f0daa5f7
16 changed files with 217 additions and 100 deletions

View File

@ -29400,3 +29400,44 @@ Apologies for any names omitted.
Uploaded the wrong postfix-3.11-20250713 tarball. Files:
master/event_server.c, master/multi_server.c.
Deleted an <openssl/engine.h> dependency, because the feature is
being removed from OpenSSL, and Postfix no longer needs it. File:
posttls-finger/posttls-finger.c.
Updated the proxymap(8) manpage and some internal documentation.
File: proxymap/proxymap.c.
20250715
Cleanup: the proxymap 'open' service always returns the
dict->flags from a newly-initialized instance. This avoids
cross-talk between different clients. File: proxymap/proxymap.c.
20250716
Bugfix (defect introduced: Postfix 2.7, date 20121223):
segfault in the internal: table iterator when the table
contained exactly one element. File: util/htable.c.
Technical debt: allow an element to be deleted before the
internal: table's first/next iterator has visited it. File:
util/htable.c.
20250716
Bugfix (defect introduced: Postfix 2.8, date 20101230):
after detecting a cache table change and before starting a
new postscreen process, the old postscreen process did not
close the postscreen_cache_map, and therefore kept an
exclusive lock that could prevent a new postscreen process
from starting. Problem reported by Florian Piekert. File:
postscreen/postscreen.c.
20250717
Workaround: Postfix daemons no longer automatically restart
after a btree:, dbm:, hash:, lmdb:, or sdbm: table file
modification time change, when they opened that table for
writing. Files: util/dict.c, util/dict_db.c, util/dict_dbm.c,
util/dict_lmdb.c, util/dict_sdbm.c.

View File

@ -222,7 +222,7 @@ POSTSCREEN(8) POSTSCREEN(8)
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet).
<b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (normal: 6s, overload: 2s)</b>
<b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (normal: 6s, <a href="STRESS_README.html">overload</a>: 2s)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for an SMTP
client to send a command before its turn, and for DNS blocklist
lookup results to arrive (default: up to 2 seconds under stress,
@ -359,7 +359,7 @@ POSTSCREEN(8) POSTSCREEN(8)
The limit on the total number of commands per SMTP session for
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
<b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (normal: 300s, overload: 10s)</b>
<b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (normal: 300s, <a href="STRESS_README.html">overload</a>: 10s)</b>
The time limit to read an entire command line with
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
@ -405,7 +405,7 @@ POSTSCREEN(8) POSTSCREEN(8)
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
The maximal number of digits after the decimal point when log-
ging sub-second delay values.
ging delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative commands.
@ -468,5 +468,8 @@ POSTSCREEN(8) POSTSCREEN(8)
111 8th Avenue
New York, NY 10011, USA
Wietse Venema
porcupine.org
POSTSCREEN(8)
</pre> </body> </html>

View File

@ -45,51 +45,60 @@ PROXYMAP(8) PROXYMAP(8)
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server implements the following requests:
<b>open</b> <i>maptype:mapname flags</i>
Open the table with type <i>maptype</i> and name <i>mapname</i>, as controlled
by <i>flags</i>. The reply includes the <i>maptype</i> dependent flags (to
distinguish a fixed string table from a regular expression ta-
ble).
<b>open</b> <i>maptype:mapname instance-flags</i>
Open the table with type <i>maptype</i> and name <i>mapname</i>, with initial
dictionary flags <i>instance-flags</i>. The reply contains the actual
dictionary flags (for example, to distinguish a fixed-string ta-
ble from a regular-expression table).
<b>lookup</b> <i>maptype:mapname flags key</i>
Look up the data stored under the requested key. The reply is
the request completion status code and the lookup result value.
The <i>maptype:mapname</i> and <i>flags</i> are the same as with the <b>open</b>
<b>lookup</b> <i>maptype:mapname instance-flags request-flags key</i>
Look up the data stored under the requested key using the dic-
tionary flags in <i>request-flags</i>. The reply contains the request
completion status code, the resulting dictionary flags, and the
lookup result value. The <i>maptype:mapname</i> and <i>instance-flags</i> are
the same as with the <b>open</b> request.
<b>update</b> <i>maptype:mapname instance-flags request-flags key value</i>
Update the data stored under the requested key using the dictio-
nary flags in <i>request-flags</i>. The reply contains the request
completion status code and the resulting dictionary flags. The
<i>maptype:mapname</i> and <i>instance-flags</i> are the same as with the <b>open</b>
request.
<b>update</b> <i>maptype:mapname flags key value</i>
Update the data stored under the requested key. The reply is
the request completion status code. The <i>maptype:mapname</i> and
<i>flags</i> are the same as with the <b>open</b> request.
To implement single-updater maps, specify a process limit of 1
To implement single-updater maps, specify a process limit of 1
in the <a href="master.5.html">master.cf</a> file entry for the <b>proxywrite</b> service.
This request is supported in Postfix 2.5 and later.
<b>delete</b> <i>maptype:mapname flags key</i>
Delete the data stored under the requested key. The reply is
the request completion status code. The <i>maptype:mapname</i> and
<i>flags</i> are the same as with the <b>open</b> request.
<b>delete</b> <i>maptype:mapname instance-flags request-flags key</i>
Delete the data stored under the requested key, using the dic-
tionary flags in <i>request-flags</i>. The reply contains the request
completion status code and the resulting dictionary flags. The
<i>maptype:mapname</i> and <i>instance-flags</i> are the same as with the <b>open</b>
request.
This request is supported in Postfix 2.5 and later.
<b>sequence</b> <i>maptype:mapname flags function</i>
Iterate over the specified database. The <i>function</i> is one of
DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT. The reply is the
request completion status code and a lookup key and result
value, if found.
<b>sequence</b> <i>maptype:mapname instance-flags request-flags function</i>
Iterate over the specified database, using the dictionary flags
in <i>request-flags</i>. The <i>function</i> is either DICT_SEQ_FUN_FIRST or
DICT_SEQ_FUN_NEXT. The reply contains the request completion
status code, the resulting dictionary flags, and a lookup key
and result value if found. The <i>maptype:mapname</i> and
<i>instance-flags</i> are the same as with the <b>open</b> request.
This request is supported in Postfix 2.9 and later.
Not implemented: close
There is no <b>close</b> request, nor are tables implicitly closed when
a client disconnects. The purpose is to share tables among mul-
tiple client processes. Due to the absence of an explicit or
implicit <b>close</b>, updates are forced to be synchronous.
The request completion status is one of OK, RETRY, NOKEY (lookup failed
because the key was not found), BAD (malformed request) or DENY (the
table is not approved for proxy read or update access).
There is no <b>close</b> command, nor are tables implicitly closed when a
client disconnects. The purpose is to share tables among multiple
client processes.
<b><a name="server_process_management">SERVER PROCESS MANAGEMENT</a></b>
<a href="proxymap.8.html"><b>proxymap</b>(8)</a> servers run under control by the Postfix <a href="master.8.html"><b>master</b>(8)</a> server.
Each server can handle multiple simultaneous connections. When all
@ -219,5 +228,8 @@ PROXYMAP(8) PROXYMAP(8)
111 8th Avenue
New York, NY 10011, USA
Wietse Venema
porcupine.org
PROXYMAP(8)
</pre> </body> </html>

View File

@ -410,7 +410,7 @@ The default location of the Postfix main.cf and master.cf
configuration files.
.IP "\fBdelay_logging_resolution_limit (2)\fR"
The maximal number of digits after the decimal point when logging
sub\-second delay values.
delay values.
.IP "\fBcommand_directory (see 'postconf -d' output)\fR"
The location of all postfix administrative commands.
.IP "\fBmax_idle (100s)\fR"
@ -480,3 +480,6 @@ Wietse Venema
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
Wietse Venema
porcupine.org

View File

@ -46,21 +46,24 @@ that do not reliably support multiple writers (i.e. all
file\-based tables that are not based on \fBlmdb\fR).
.PP
The \fBproxymap\fR(8) server implements the following requests:
.IP "\fBopen\fR \fImaptype:mapname flags\fR"
.IP "\fBopen\fR \fImaptype:mapname instance\-flags\fR"
Open the table with type \fImaptype\fR and name \fImapname\fR,
as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
dependent flags (to distinguish a fixed string table from a regular
expression table).
.IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
Look up the data stored under the requested key.
The reply is the request completion status code and
the lookup result value.
The \fImaptype:mapname\fR and \fIflags\fR are the same
with initial dictionary flags \fIinstance\-flags\fR. The reply
contains the actual dictionary flags (for example, to distinguish
a fixed\-string table from a regular\-expression table).
.IP "\fBlookup\fR \fImaptype:mapname instance\-flags request\-flags key\fR"
Look up the data stored under the requested key using the
dictionary flags in \fIrequest\-flags\fR.
The reply contains the request completion status code, the
resulting dictionary flags, and the lookup result value.
The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
Update the data stored under the requested key.
The reply is the request completion status code.
The \fImaptype:mapname\fR and \fIflags\fR are the same
.IP "\fBupdate\fR \fImaptype:mapname instance\-flags request\-flags key value\fR"
Update the data stored under the requested key using the
dictionary flags in \fIrequest\-flags\fR.
The reply contains the request completion status code and the
resulting dictionary flags.
The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.sp
To implement single\-updater maps, specify a process limit
@ -68,29 +71,36 @@ of 1 in the master.cf file entry for the \fBproxywrite\fR
service.
.sp
This request is supported in Postfix 2.5 and later.
.IP "\fBdelete\fR \fImaptype:mapname flags key\fR"
Delete the data stored under the requested key.
The reply is the request completion status code.
The \fImaptype:mapname\fR and \fIflags\fR are the same
.IP "\fBdelete\fR \fImaptype:mapname instance\-flags request\-flags key\fR"
Delete the data stored under the requested key, using the
dictionary flags in \fIrequest\-flags\fR.
The reply contains the request completion status code and the
resulting dictionary flags.
The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.sp
This request is supported in Postfix 2.5 and later.
.IP "\fBsequence\fR \fImaptype:mapname flags function\fR"
Iterate over the specified database. The \fIfunction\fR
is one of DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
The reply is the request completion status code and
a lookup key and result value, if found.
.IP "\fBsequence\fR \fImaptype:mapname instance\-flags request\-flags function\fR"
Iterate over the specified database, using the dictionary flags
in \fIrequest\-flags\fR. The \fIfunction\fR is either
DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
The reply contains the request completion status code, the
resulting dictionary flags, and a lookup key and result value
if found.
The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.sp
This request is supported in Postfix 2.9 and later.
.IP "Not implemented: close"
There is no \fBclose\fR request, nor are tables implicitly closed
when a client disconnects. The purpose is to share tables among
multiple client processes. Due to the absence of an explicit or
implicit \fBclose\fR, updates are forced to be synchronous.
.PP
The request completion status is one of OK, RETRY, NOKEY
(lookup failed because the key was not found), BAD (malformed
request) or DENY (the table is not approved for proxy read
or update access).
There is no \fBclose\fR command, nor are tables implicitly closed
when a client disconnects. The purpose is to share tables among
multiple client processes.
.SH "SERVER PROCESS MANAGEMENT"
.na
.nf
@ -241,3 +251,6 @@ Wietse Venema
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
Wietse Venema
porcupine.org

View File

@ -181,3 +181,5 @@ proto proto COMPATIBILITY_README html
proxymap proxymap c
postmap postmap c postalias postalias c
client Files dict h dict_proxy c proxymap proxymap c
cross talk between different clients File proxymap proxymap c
postscreen postscreen c

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20250714"
#define MAIL_RELEASE_DATE "20250717"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT

View File

@ -370,7 +370,7 @@
/* configuration files.
/* .IP "\fBdelay_logging_resolution_limit (2)\fR"
/* The maximal number of digits after the decimal point when logging
/* sub-second delay values.
/* delay values.
/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
/* The location of all postfix administrative commands.
/* .IP "\fBmax_idle (100s)\fR"
@ -430,6 +430,9 @@
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
/* Wietse Venema
/* porcupine.org
/*--*/
/* System library. */
@ -996,7 +999,7 @@ static void pre_accept(char *unused_name, char **unused_argv)
if (new_event_time >= last_event_time + 1
&& (name = dict_changed_name()) != 0) {
msg_info("table %s has changed - finishing in the background", name);
event_server_drain();
psc_drain(unused_name, unused_argv);
} else {
last_event_time = new_event_time;
}

View File

@ -414,7 +414,6 @@
#ifdef USE_TLS
#include <tls_proxy.h>
#include <openssl/engine.h>
#endif
/*

View File

@ -40,21 +40,24 @@
/* file-based tables that are not based on \fBlmdb\fR).
/* .PP
/* The \fBproxymap\fR(8) server implements the following requests:
/* .IP "\fBopen\fR \fImaptype:mapname flags\fR"
/* .IP "\fBopen\fR \fImaptype:mapname instance-flags\fR"
/* Open the table with type \fImaptype\fR and name \fImapname\fR,
/* as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
/* dependent flags (to distinguish a fixed string table from a regular
/* expression table).
/* .IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
/* Look up the data stored under the requested key.
/* The reply is the request completion status code and
/* the lookup result value.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* with initial dictionary flags \fIinstance-flags\fR. The reply
/* contains the actual dictionary flags (for example, to distinguish
/* a fixed-string table from a regular-expression table).
/* .IP "\fBlookup\fR \fImaptype:mapname instance-flags request-flags key\fR"
/* Look up the data stored under the requested key using the
/* dictionary flags in \fIrequest-flags\fR.
/* The reply contains the request completion status code, the
/* resulting dictionary flags, and the lookup result value.
/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
/* Update the data stored under the requested key.
/* The reply is the request completion status code.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* .IP "\fBupdate\fR \fImaptype:mapname instance-flags request-flags key value\fR"
/* Update the data stored under the requested key using the
/* dictionary flags in \fIrequest-flags\fR.
/* The reply contains the request completion status code and the
/* resulting dictionary flags.
/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* To implement single-updater maps, specify a process limit
@ -62,29 +65,36 @@
/* service.
/* .sp
/* This request is supported in Postfix 2.5 and later.
/* .IP "\fBdelete\fR \fImaptype:mapname flags key\fR"
/* Delete the data stored under the requested key.
/* The reply is the request completion status code.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* .IP "\fBdelete\fR \fImaptype:mapname instance-flags request-flags key\fR"
/* Delete the data stored under the requested key, using the
/* dictionary flags in \fIrequest-flags\fR.
/* The reply contains the request completion status code and the
/* resulting dictionary flags.
/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* This request is supported in Postfix 2.5 and later.
/* .IP "\fBsequence\fR \fImaptype:mapname flags function\fR"
/* Iterate over the specified database. The \fIfunction\fR
/* is one of DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
/* The reply is the request completion status code and
/* a lookup key and result value, if found.
/* .IP "\fBsequence\fR \fImaptype:mapname instance-flags request-flags function\fR"
/* Iterate over the specified database, using the dictionary flags
/* in \fIrequest-flags\fR. The \fIfunction\fR is either
/* DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
/* The reply contains the request completion status code, the
/* resulting dictionary flags, and a lookup key and result value
/* if found.
/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* This request is supported in Postfix 2.9 and later.
/* .IP "Not implemented: close"
/* There is no \fBclose\fR request, nor are tables implicitly closed
/* when a client disconnects. The purpose is to share tables among
/* multiple client processes. Due to the absence of an explicit or
/* implicit \fBclose\fR, updates are forced to be synchronous.
/* .PP
/* The request completion status is one of OK, RETRY, NOKEY
/* (lookup failed because the key was not found), BAD (malformed
/* request) or DENY (the table is not approved for proxy read
/* or update access).
/*
/* There is no \fBclose\fR command, nor are tables implicitly closed
/* when a client disconnects. The purpose is to share tables among
/* multiple client processes.
/* SERVER PROCESS MANAGEMENT
/* .ad
/* .fi
@ -215,6 +225,9 @@
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
/* Wietse Venema
/* porcupine.org
/*--*/
/* System library. */
@ -323,6 +336,8 @@ static char *get_nested_dict_name(char *type_name)
static DICT *proxy_map_find(const char *map_type_name, int inst_flags,
int *statp)
{
static HTABLE *new_flags;
HTABLE_INFO *ht;
DICT *dict;
#define PROXY_COLON DICT_TYPE_PROXY ":"
@ -360,6 +375,20 @@ static DICT *proxy_map_find(const char *map_type_name, int inst_flags,
inst_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
/*
* Remember the mapping from dict->reg_name to the dict->flags of a
* newly-initialized instance. Always return an instance with those new
* dict->flags, to avoid crosstalk between different clients.
*/
if (new_flags == 0)
new_flags = htable_create(100);
if ((ht = htable_locate(new_flags, dict->reg_name)) == 0) {
(void) htable_enter(new_flags, dict->reg_name,
CAST_INT_TO_VOID_PTR(dict->flags));
} else {
dict->flags = CAST_ANY_PTR_TO_INT(ht->value);
}
dict->error = 0;
return (dict);
}

View File

@ -160,8 +160,8 @@
/* .IP "char *context"
/* Application context from the caller.
/* .PP
/* dict_changed_name() returns non-zero when any dictionary needs to
/* be re-opened because it has changed or because it was unlinked.
/* dict_changed_name() returns non-zero when any dictionary is
/* opened read-only and has changed, or because it was unlinked.
/* A non-zero result is the name of a changed dictionary.
/*
/* dict_load_file_xt() reads name-value entries from the named file.
@ -641,11 +641,12 @@ const char *dict_changed_name(void)
dict = ((DICT_NODE *) h->value)->dict;
if (dict->stat_fd < 0) /* not file-based */
continue;
if (dict->mtime == 0) /* not bloody likely */
msg_warn("%s: table %s: null time stamp", myname, h->key);
if (dict->mtime < 0) /* not bloody likely */
msg_warn("%s: table %s: negative time stamp", myname, h->key);
if (fstat(dict->stat_fd, &st) < 0)
msg_fatal("%s: fstat: %m", myname);
if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0
&& dict->mtime > 0
&& st.st_mtime != dict->mtime)
|| st.st_nlink == 0)
status = h->key;

View File

@ -789,7 +789,8 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
dict_db->dict.stat_fd = dbfd;
if (fstat(dict_db->dict.stat_fd, &st) < 0)
msg_fatal("dict_db_open: fstat: %m");
dict_db->dict.mtime = st.st_mtime;
if (open_flags == O_RDONLY)
dict_db->dict.mtime = st.st_mtime;
dict_db->dict.owner.uid = st.st_uid;
dict_db->dict.owner.status = (st.st_uid != 0);

View File

@ -472,7 +472,8 @@ DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags)
msg_fatal("open database %s: cannot support GDBM", path);
if (fstat(dict_dbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_dbm_open: fstat: %m");
dict_dbm->dict.mtime = st.st_mtime;
if (open_mode == O_RDONLY)
dict_dbm->dict.mtime = st.st_mtime;
dict_dbm->dict.owner.uid = st.st_uid;
dict_dbm->dict.owner.status = (st.st_uid != 0);

View File

@ -653,7 +653,8 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags)
msg_fatal("dict_lmdb_open: fstat: %m");
dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd;
dict_lmdb->dict.lock_type = MYFLOCK_STYLE_FCNTL;
dict_lmdb->dict.mtime = st.st_mtime;
if (open_flags == O_RDONLY)
dict_lmdb->dict.mtime = st.st_mtime;
dict_lmdb->dict.owner.uid = st.st_uid;
dict_lmdb->dict.owner.status = (st.st_uid != 0);

View File

@ -449,7 +449,8 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags)
dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm);
if (fstat(dict_sdbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_sdbm_open: fstat: %m");
dict_sdbm->dict.mtime = st.st_mtime;
if (open_flags == O_RDONLY)
dict_sdbm->dict.mtime = st.st_mtime;
dict_sdbm->dict.owner.uid = st.st_uid;
dict_sdbm->dict.owner.status = (st.st_uid != 0);

View File

@ -93,8 +93,7 @@
/* htable_sequence() returns the first or next element depending
/* on the value of the "how" argument. Specify HTABLE_SEQ_FIRST
/* to start a new sequence, HTABLE_SEQ_NEXT to continue, and
/* HTABLE_SEQ_STOP to terminate a sequence early. The caller
/* must not delete an element before it is visited.
/* HTABLE_SEQ_STOP to terminate a sequence early.
/* RESTRICTIONS
/* A callback function should not modify the hash table that is
/* specified to its caller.
@ -272,7 +271,7 @@ HTABLE_INFO *htable_locate(HTABLE *table, const char *key)
void htable_delete(HTABLE *table, const char *key, void (*free_fn) (void *))
{
if (table) {
HTABLE_INFO *ht;
HTABLE_INFO *ht, **sp;
HTABLE_INFO **h = table->data + htable_hash(key, table->size);
#define STREQ(x,y) (x == y || (x[0] == y[0] && strcmp(x,y) == 0))
@ -290,6 +289,14 @@ void htable_delete(HTABLE *table, const char *key, void (*free_fn) (void *))
if (free_fn && ht->value)
(*free_fn) (ht->value);
myfree((void *) ht);
/* In case the first/next iterator has not yet visited it */
for (sp = table->seq_element; sp && *sp; sp++) {
if (*sp == ht) {
while ((*sp = sp[1]) != 0)
sp += 1;
break;
}
}
return;
}
}
@ -374,7 +381,7 @@ HTABLE_INFO *htable_sequence(HTABLE *table, int how)
myfree((void *) table->seq_bucket);
table->seq_bucket = htable_list(table);
table->seq_element = table->seq_bucket;
return (*(table->seq_element)++);
/* FALLTHROUGH */
case HTABLE_SEQ_NEXT: /* next element */
if (table->seq_element && *table->seq_element)
return (*(table->seq_element)++);