Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2025-07-27 16:54:27 +08:00
72 changed files with 6975 additions and 2959 deletions

View File

@ -231,7 +231,7 @@ menu "Target Images"
config GRUB_IMAGES
bool "Build GRUB images (Linux x86 or x86_64 host only)"
depends on TARGET_x86
depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS
depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS || TARGET_ROOTFS_EROFS
select PACKAGE_grub2
select PACKAGE_grub2-bios-setup
default y
@ -239,7 +239,7 @@ menu "Target Images"
config GRUB_EFI_IMAGES
bool "Build GRUB EFI images"
depends on TARGET_x86 || TARGET_armsr || TARGET_loongarch64
depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS
depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS || TARGET_ROOTFS_EROFS
select PACKAGE_grub2 if TARGET_x86
select PACKAGE_grub2-efi if TARGET_x86
select PACKAGE_grub2-bios-setup if TARGET_x86

View File

@ -126,10 +126,12 @@ $(eval $(call SetupHostCommand,diff,Please install GNU diffutils, \
diff --version 2>&1 | grep GNU))
$(eval $(call SetupHostCommand,cp,Please install GNU fileutils, \
$(TOPDIR)/staging_dir/host/bin/gcp --help 2>&1 | grep 'Copy SOURCE', \
gcp --help 2>&1 | grep 'Copy SOURCE', \
cp --help 2>&1 | grep 'Copy SOURCE'))
$(eval $(call SetupHostCommand,seq,Please install seq, \
$(TOPDIR)/staging_dir/host/bin/gseq --version, \
gseq --version, \
seq --version 2>&1 | grep seq))
@ -153,10 +155,12 @@ $(eval $(call SetupHostCommand,getopt, \
/opt/local/bin/getopt -o t --long test -- --test | grep '^ *--test *--'))
$(eval $(call SetupHostCommand,realpath,Please install a 'realpath' utility, \
$(TOPDIR)/staging_dir/host/bin/grealpath /, \
grealpath /, \
realpath /))
$(eval $(call SetupHostCommand,stat,Cannot find a file stat utility, \
$(TOPDIR)/staging_dir/host/bin/gstat -c%s $(TOPDIR)/Makefile, \
gnustat -c%s $(TOPDIR)/Makefile, \
gstat -c%s $(TOPDIR)/Makefile, \
stat -c%s $(TOPDIR)/Makefile))
@ -175,6 +179,7 @@ $(eval $(call SetupHostCommand,wget,Please install GNU 'wget', \
wget --version | grep GNU))
$(eval $(call SetupHostCommand,install,Please install GNU 'install', \
$(TOPDIR)/staging_dir/host/bin/ginstall --version | grep GNU, \
install --version | grep GNU, \
ginstall --version | grep GNU))

View File

@ -113,7 +113,7 @@ define SetupHostCommand
[ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \
;; \
esac; \
ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \
ln -sf "$$$$$$$${bin#$(STAGING_DIR_HOST)/bin/}" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \
exit 1; \
fi; \
fi; \

View File

@ -559,18 +559,6 @@ endef
$(eval $(call KernelPackage,crypto-kpp))
define KernelPackage/crypto-lib-aescfb
TITLE:=AES cipher operations feedback mode library
DEPENDS:=@!LINUX_6_6
HIDDEN:=1
KCONFIG:=CONFIG_CRYPTO_LIB_AESCFB
FILES:=$(LINUX_DIR)/lib/crypto/libaescfb.ko
AUTOLOAD:=$(call AutoLoad,09,libaescfb)
$(call AddDepends/crypto)
endef
$(eval $(call KernelPackage,crypto-lib-aescfb))
define KernelPackage/crypto-lib-chacha20
TITLE:=ChaCha library interface
KCONFIG:=CONFIG_CRYPTO_LIB_CHACHA

View File

@ -620,7 +620,7 @@ $(eval $(call KernelPackage,drm-imx))
define KernelPackage/drm-imx-hdmi
SUBMENU:=$(VIDEO_MENU)
TITLE:=Freescale i.MX HDMI DRM support
DEPENDS:=+kmod-sound-core kmod-drm-imx kmod-drm-display-helper
DEPENDS:=+kmod-sound-core kmod-drm-imx +kmod-drm-display-helper
KCONFIG:=CONFIG_DRM_IMX_HDMI \
CONFIG_DRM_DW_HDMI_AHB_AUDIO \
CONFIG_DRM_DW_HDMI_I2S_AUDIO

View File

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gettext-full
PKG_VERSION:=0.22.5
PKG_VERSION:=0.24.1
PKG_RELEASE:=1
PKG_SOURCE:=gettext-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@GNU/gettext
PKG_HASH:=fe10c37353213d78a5b83d48af231e005c4da84db5ce88037d88355938259640
PKG_HASH:=6164ec7aa61653ac9cdfb41d5c2344563b21f707da1562712e48715f1d2052a6
PKG_BUILD_DIR:=$(BUILD_DIR)/gettext-$(PKG_VERSION)
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/gettext-$(PKG_VERSION)
@ -27,7 +27,7 @@ PKG_BUILD_PARALLEL:=0
PKG_FIXUP:=autoreconf
HOST_BUILD_DEPENDS:=gperf/host libiconv-full/host libunistring/host libxml2/host
HOST_BUILD_DEPENDS:=gnulib-l10n/host gperf/host libiconv-full/host libunistring/host libxml2/host
HOST_BUILD_PARALLEL:=0
PKG_SUBDIRS:= \

View File

@ -1,6 +1,6 @@
--- a/autogen.sh
+++ b/autogen.sh
@@ -81,6 +81,7 @@ if ! $skip_gnulib; then
@@ -104,6 +104,7 @@ if ! $skip_gnulib; then
getopt-gnu
gettext-h
havelib
@ -18,4 +18,4 @@
+LDADD = ../gnulib-lib/libgrt.a $(LTLIBUNISTRING) @LTLIBINTL@ @LTLIBICONV@ $(WOE32_LDADD)
# Specify installation directory, for --enable-relocatable.
gettext_CFLAGS = -DINSTALLDIR=\"$(bindir)\"
gettext_CFLAGS = -DINSTALLDIR=$(bindir_c_make)

View File

@ -0,0 +1,37 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gnulib-l10n
PKG_CPE_ID:=cpe:/a:gnu:$(PKG_NAME)
PKG_VERSION:=20241231
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/gnulib
PKG_HASH:=155752ba6796aa294cde87c2bf0e771a5891eeeacb131345be0e080a3ec0ceea
include $(INCLUDE_DIR)/host-build.mk
include $(INCLUDE_DIR)/package.mk
define Package/gnulib-l10n
SECTION:=libs
CATEGORY:=Libraries
TITLE:=GNU Gnulib localization translation files
URL:=http://www.gnu.org/software/gnulib/
endef
define Package/gnulib-l10n/description
Localizations (translations) of messages for GNU gnulib code.
endef
HOST_CONFIGURE_ARGS += \
--localedir=$(HOST_BUILD_PREFIX)/share/locale
define Host/Uninstall
-$(call Host/Compile/Default,uninstall)
endef
define Package/gnulib-l10n/install
$(call Build/Install/Default,install SUBDIRS='$(PKG_SUBDIRS)')
endef
$(eval $(call HostBuild))
$(eval $(call BuildPackage,gnulib-l10n))

View File

@ -17,7 +17,6 @@ PKG_MAINTAINER:=
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=COPYING
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
PKG_BUILD_FLAGS:=lto

View File

@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=selinux-policy
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://git.defensec.nl/selinux-policy.git
PKG_VERSION:=2.6
PKG_MIRROR_HASH:=3604ce2d2874f58a7fc03998daa81628fca43aa8ac0a7436f07612365b6ce7ad
PKG_VERSION:=2.8.2
PKG_MIRROR_HASH:=7e81e6e9e933e6409b7f7bf2d5639960c440c82589c99b199b3540676f88eb8a
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
PKG_BUILD_DEPENDS:=secilc/host policycoreutils/host

View File

@ -0,0 +1,51 @@
From 850a6d031039237b0b13d8fab9f10a7cd4752907 Mon Sep 17 00:00:00 2001
From: Dominick Grift <dominick.grift@defensec.nl>
Date: Sat, 5 Apr 2025 13:40:26 +0200
Subject: [PATCH] loginutils/login.c: libselinux get_default_context() expects
seuser
Use getseuserbyname() to get the seuser associated with username and use that
instead with get_default_context()
>From get_default_context.3:
"These functions takes a SELinux user identity that must be defined in the SELinux policy as their input, not a Linux username."
Fixes: #19075
Upstream-Status: Submitted [https://lists.busybox.net/pipermail/busybox/2025-April/091407.html]
Signed-off-by: Dominick Grift <dominick.grift@defensec.nl>
---
loginutils/login.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -183,12 +183,16 @@ static void die_if_nologin(void)
static void initselinux(char *username, char *full_tty,
security_context_t *user_sid)
{
+ char *seuser = NULL, *level = NULL;
security_context_t old_tty_sid, new_tty_sid;
if (!is_selinux_enabled())
return;
- if (get_default_context(username, NULL, user_sid)) {
+ if (getseuserbyname(username, &seuser, &level)) {
+ bb_error_msg_and_die("can't get seuser for %s", username);
+ }
+ if (get_default_context(seuser, NULL, user_sid)) {
bb_error_msg_and_die("can't get SID for %s", username);
}
if (getfilecon(full_tty, &old_tty_sid) < 0) {
@@ -201,6 +205,11 @@ static void initselinux(char *username,
if (setfilecon(full_tty, new_tty_sid) != 0) {
bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid);
}
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(seuser);
+ free(level);
+ }
}
#endif

View File

@ -163,6 +163,7 @@ sub download
my $mirror = shift;
my $download_filename = shift;
my @additional_mirrors = @_;
my @cmd;
$mirror =~ s!/$!!;
@ -209,7 +210,11 @@ sub download
}
};
} else {
my @cmd = download_cmd("$mirror/$download_filename", $download_filename, @additional_mirrors);
if ($mirror =~ /a=snapshot/) {
@cmd = download_cmd("$mirror", $download_filename, @additional_mirrors);
} else {
@cmd = download_cmd("$mirror/$download_filename", $download_filename, @additional_mirrors);
}
print STDERR "+ ".join(" ",@cmd)."\n";
open(FETCH_FD, '-|', @cmd) or die "Cannot launch aria2c, curl or wget.\n";
$hash_cmd and do {
@ -325,14 +330,23 @@ if (-f "$target/$filename") {
$download_tool = select_tool();
my $mirror = shift @mirrors;
# Try snapshot original source last
if ($mirror =~ /snapshot/) {
push @mirrors, $mirror;
$mirror = shift @mirrors;
}
while (!-f "$target/$filename") {
my $mirror = shift @mirrors;
$mirror or die "No more mirrors to try - giving up.\n";
download($mirror, $url_filename, @mirrors);
if (!-f "$target/$filename" && $url_filename ne $filename) {
download($mirror, $filename, @mirrors);
}
$mirror = shift @mirrors;
}
$SIG{INT} = \&cleanup;

View File

@ -135,7 +135,7 @@ endef
# A reasonable set of default packages handling the NAS type
# of devices out of the box (former NAS42x0 IcyBox defaults)
GEMINI_NAS_PACKAGES := $(DEFAULT_PACKAGES.nas) \
kmod-md-mod kmod-md-linear kmod-md-multipath \
kmod-md-mod kmod-md-linear \
kmod-md-raid0 kmod-md-raid1 kmod-md-raid10 kmod-md-raid456 \
kmod-fs-btrfs kmod-fs-cifs kmod-fs-nfs \
kmod-fs-nfsd kmod-fs-ntfs3 kmod-fs-reiserfs kmod-fs-vfat \

View File

@ -108,6 +108,8 @@
pinctrl-0 = <&mdio_pins>;
pinctrl-names = "default";
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
@ -367,6 +369,8 @@
nvmem-cells = <&eeprom_factory_0>;
nvmem-cell-names = "eeprom";
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
band@0 {
reg = <0>;

View File

@ -13,6 +13,7 @@
#include <asm/mips-cps.h>
#include <asm/prom.h>
#include <asm/smp-ops.h>
#include <linux/smp.h>
#include <mach-rtl83xx.h>
@ -41,13 +42,13 @@ static void rtlsmp_finish(void)
{
/* These devices are low on resources. There might be the chance that CEVT_R4K is
* not enabled in kernel build. Nevertheless the timer and interrupt 7 might be
* active by default after startup of secondary VPE. With no registered handler
* that leads to continuous unhandeled interrupts. In this case disable counting
* (DC) in the core and confirm a pending interrupt.
* active by default after startup of secondary VPEs. With no registered handler
* that leads to continuous unhandeled interrupts. Disable it but keep the counter
* running so it can still be used as an entropy source.
*/
if (!IS_ENABLED(CONFIG_CEVT_R4K)) {
write_c0_cause(read_c0_cause() | CAUSEF_DC);
write_c0_compare(0);
write_c0_status(read_c0_status() & ~CAUSEF_IP7);
write_c0_compare(read_c0_count() - 1);
}
local_irq_enable();

View File

@ -29,6 +29,9 @@ extern const struct dsa_switch_ops rtl930x_switch_ops;
extern const struct phylink_pcs_ops rtl83xx_pcs_ops;
extern const struct phylink_pcs_ops rtl93xx_pcs_ops;
extern int rtmdio_838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtmdio_838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
DEFINE_MUTEX(smi_lock);
int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
@ -244,7 +247,7 @@ int read_phy(u32 port, u32 page, u32 reg, u32 *val)
{
switch (soc_info.family) {
case RTL8380_FAMILY_ID:
return rtl838x_read_phy(port, page, reg, val);
return rtmdio_838x_read_phy(port, page, reg, val);
case RTL8390_FAMILY_ID:
return rtl839x_read_phy(port, page, reg, val);
case RTL9300_FAMILY_ID:
@ -260,7 +263,7 @@ int write_phy(u32 port, u32 page, u32 reg, u32 val)
{
switch (soc_info.family) {
case RTL8380_FAMILY_ID:
return rtl838x_write_phy(port, page, reg, val);
return rtmdio_838x_write_phy(port, page, reg, val);
case RTL8390_FAMILY_ID:
return rtl839x_write_phy(port, page, reg, val);
case RTL9300_FAMILY_ID:

View File

@ -340,51 +340,56 @@ static int rtl93xx_get_sds(struct phy_device *phydev)
return sds_num;
}
static void rtl83xx_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
static void rtldsa_83xx_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state)
{
struct rtl838x_pcs *rtpcs = container_of(pcs, struct rtl838x_pcs, pcs);
struct rtl838x_switch_priv *priv = rtpcs->priv;
int port = rtpcs->port;
u64 speed;
u64 link;
if (port < 0 || port > priv->cpu_port) {
state->link = false;
return;
}
state->link = 0;
link = priv->r->get_port_reg_le(priv->r->mac_link_sts);
if (link & BIT_ULL(port))
state->link = 1;
pr_debug("%s: link state port %d: %llx\n", __func__, port, link & BIT_ULL(port));
state->speed = SPEED_UNKNOWN;
state->duplex = DUPLEX_UNKNOWN;
state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
if (port < 0 || port > priv->cpu_port)
return;
if (!(priv->r->get_port_reg_le(priv->r->mac_link_sts) & BIT_ULL(port)))
return;
state->link = 1;
state->duplex = 0;
if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port))
state->duplex = 1;
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
speed = priv->r->get_port_reg_le(priv->r->mac_link_spd_sts(port));
speed >>= (port % 16) << 1;
switch (speed & 0x3) {
case 0:
speed = (speed >> ((port % 16) << 1)) & 0x3;
switch (speed) {
case RTL_SPEED_10:
state->speed = SPEED_10;
break;
case 1:
case RTL_SPEED_100:
state->speed = SPEED_100;
break;
case 2:
case RTL_SPEED_1000:
state->speed = SPEED_1000;
break;
case 3:
if (priv->family_id == RTL9300_FAMILY_ID
&& (port == 24 || port == 26)) /* Internal serdes */
state->speed = SPEED_2500;
else
state->speed = SPEED_100; /* Is in fact 500Mbit */
/*
* This is ok so far but with minor inconsistencies. On RTL838x this setting is
* for either 500M or 2G. It might be that MAC_GLITE_STS register tells more. On
* RTL839x these vendor specifics are derived from MAC_LINK_500M_STS and mode 3
* is 10G. This is of interest so resolve to it. Sadly it is off by one for the
* current RTL_SPEED_10000 (=4) definition for RTL93xx.
*/
state->speed = SPEED_10000;
break;
}
state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
if (priv->r->get_port_reg_le(priv->r->mac_rx_pause_sts) & BIT_ULL(port))
state->pause |= MLO_PAUSE_RX;
if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
@ -2046,7 +2051,7 @@ static int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_re
const struct phylink_pcs_ops rtl83xx_pcs_ops = {
.pcs_an_restart = rtl83xx_pcs_an_restart,
.pcs_get_state = rtl83xx_pcs_get_state,
.pcs_get_state = rtldsa_83xx_pcs_get_state,
.pcs_config = rtl83xx_pcs_config,
};

View File

@ -1768,169 +1768,6 @@ irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
int rtl838x_smi_wait_op(int timeout)
{
int ret = 0;
u32 val;
ret = readx_poll_timeout(sw_r32, RTL838X_SMI_ACCESS_PHY_CTRL_1,
val, !(val & 0x1), 20, timeout);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/* Reads a register in a page from the PHY */
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
{
u32 v, park_page = 0x1f << 15;
int err;
if (port > 31) {
*val = 0xffff;
return 0;
}
if (page > 4095 || reg > 31)
return -ENOTSUPP;
mutex_lock(&smi_lock);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = reg << 20 | page << 3;
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
err = 0;
errout:
mutex_unlock(&smi_lock);
return err;
}
/* Write to a register in a page of the PHY */
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
{
u32 v, park_page = 0x1f << 15;
int err;
val &= 0xffff;
if (port > 31 || page > 4095 || reg > 31)
return -ENOTSUPP;
mutex_lock(&smi_lock);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(BIT(port), RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = reg << 20 | page << 3 | 0x4;
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
err = 0;
errout:
mutex_unlock(&smi_lock);
return err;
}
/* Read an mmd register of a PHY */
int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
{
int err;
u32 v;
mutex_lock(&smi_lock);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = addr << 16 | reg;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3);
/* mmd-access | read | cmd-start */
v = 1 << 1 | 0 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
err = 0;
errout:
mutex_unlock(&smi_lock);
return err;
}
/* Write to an mmd register of a PHY */
int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
{
int err;
u32 v;
pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
val &= 0xffff;
mutex_lock(&smi_lock);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3);
sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3);
/* mmd-access | write | cmd-start */
v = 1 << 1 | 1 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtl838x_smi_wait_op(100000);
if (err)
goto errout;
err = 0;
errout:
mutex_unlock(&smi_lock);
return err;
}
void rtl8380_get_version(struct rtl838x_switch_priv *priv)
{
u32 rw_save, info_save;

View File

@ -27,11 +27,6 @@ extern struct rtl83xx_soc_info soc_info;
extern int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data);
extern int rtl838x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
extern int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl838x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
extern int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
extern int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
extern int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl839x_read_sds_phy(int phy_addr, int phy_reg);
@ -1640,6 +1635,8 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
* reimplemented. For now it should be sufficient.
*/
DEFINE_MUTEX(rtmdio_lock);
struct rtmdio_bus_priv {
u16 id;
u16 family_id;
@ -1769,6 +1766,171 @@ static int rtmdio_838x_write_sds(int addr, int regnum, u16 val)
return 0;
}
/* RTL838x specific MDIO functions */
static int rtmdio_838x_smi_wait_op(int timeout)
{
int ret = 0;
u32 val;
ret = readx_poll_timeout(sw_r32, RTL838X_SMI_ACCESS_PHY_CTRL_1,
val, !(val & 0x1), 20, timeout);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/* Reads a register in a page from the PHY */
int rtmdio_838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
{
u32 v, park_page = 0x1f << 15;
int err;
if (port > 31) {
*val = 0xffff;
return 0;
}
if (page > 4095 || reg > 31)
return -ENOTSUPP;
mutex_lock(&rtmdio_lock);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = reg << 20 | page << 3;
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
err = 0;
errout:
mutex_unlock(&rtmdio_lock);
return err;
}
/* Write to a register in a page of the PHY */
int rtmdio_838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
{
u32 v, park_page = 0x1f << 15;
int err;
val &= 0xffff;
if (port > 31 || page > 4095 || reg > 31)
return -ENOTSUPP;
mutex_lock(&rtmdio_lock);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(BIT(port), RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = reg << 20 | page << 3 | 0x4;
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
err = 0;
errout:
mutex_unlock(&rtmdio_lock);
return err;
}
/* Read an mmd register of a PHY */
static int rtmdio_838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
{
int err;
u32 v;
mutex_lock(&rtmdio_lock);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
v = addr << 16 | reg;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3);
/* mmd-access | read | cmd-start */
v = 1 << 1 | 0 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
err = 0;
errout:
mutex_unlock(&rtmdio_lock);
return err;
}
/* Write to an mmd register of a PHY */
static int rtmdio_838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
{
int err;
u32 v;
pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
val &= 0xffff;
mutex_lock(&rtmdio_lock);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0);
mdelay(10);
sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3);
sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3);
/* mmd-access | write | cmd-start */
v = 1 << 1 | 1 << 2 | 1;
sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1);
err = rtmdio_838x_smi_wait_op(100000);
if (err)
goto errout;
err = 0;
errout:
mutex_unlock(&rtmdio_lock);
return err;
}
/* These are the core functions of our new Realtek SoC MDIO bus. */
static int rtmdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum)
@ -2215,10 +2377,10 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
priv->mii_bus->read = rtmdio_83xx_read;
priv->mii_bus->write = rtmdio_83xx_write;
priv->mii_bus->reset = rtmdio_838x_reset;
bus_priv->read_mmd_phy = rtl838x_read_mmd_phy;
bus_priv->write_mmd_phy = rtl838x_write_mmd_phy;
bus_priv->read_phy = rtl838x_read_phy;
bus_priv->write_phy = rtl838x_write_phy;
bus_priv->read_mmd_phy = rtmdio_838x_read_mmd_phy;
bus_priv->write_mmd_phy = rtmdio_838x_write_mmd_phy;
bus_priv->read_phy = rtmdio_838x_read_phy;
bus_priv->write_phy = rtmdio_838x_write_phy;
bus_priv->cpu_port = RTL838X_CPU_PORT;
bus_priv->rawpage = 0xfff;
break;

View File

@ -453,4 +453,7 @@ int phy_package_write_paged(struct phy_device *phydev, int page, u32 regnum, u16
int phy_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
int phy_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
int rtmdio_838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtmdio_838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
#endif /* _RTL838X_ETH_H */

View File

@ -98,9 +98,10 @@ $(curdir)/bison/compile := $(curdir)/flex/compile
$(curdir)/bzip2/compile := $(curdir)/cmake/compile
$(curdir)/cbootimage/compile += $(curdir)/automake/compile
$(curdir)/cmake/compile += $(curdir)/libressl/compile $(curdir)/ninja/compile $(curdir)/expat/compile $(curdir)/xz/compile $(curdir)/zlib/compile $(curdir)/zstd/compile
$(curdir)/coreutils/compile := $(curdir)/automake/compile $(curdir)/bison/compile $(curdir)/gnulib/compile
$(curdir)/dosfstools/compile := $(curdir)/automake/compile
$(curdir)/e2fsprogs/compile := $(curdir)/libtool/compile $(curdir)/util-linux/compile
$(curdir)/elfutils/compile := $(curdir)/m4/compile $(curdir)/zlib/compile $(curdir)/gnulib/compile $(curdir)/libtool/compile
$(curdir)/elfutils/compile := $(curdir)/bison/compile $(curdir)/gnulib/compile $(curdir)/m4/compile $(curdir)/zlib/compile
$(curdir)/erofs-utils/compile := $(curdir)/libtool/compile $(curdir)/xz/compile $(curdir)/lz4/compile $(curdir)/util-linux/compile
$(curdir)/fakeroot/compile := $(curdir)/libtool/compile
$(curdir)/findutils/compile := $(curdir)/bison/compile
@ -138,10 +139,17 @@ $(curdir)/util-linux/compile := $(curdir)/bison/compile $(curdir)/automake/compi
$(curdir)/yafut/compile := $(curdir)/cmake/compile
ifneq ($(HOST_OS),Linux)
$(curdir)/coreutils/compile += $(curdir)/automake/compile $(curdir)/bison/compile $(curdir)/gnulib/compile
$(curdir)/squashfs4/compile += $(curdir)/coreutils/compile
tools-y += coreutils
else
tools-$(if $(CONFIG_BUILD_ALL_HOST_TOOLS)$(CONFIG_SDK),y) += coreutils
endif
ifneq ($(filter coreutils,$(tools-y)),)
$(curdir)/elfutils/compile += $(curdir)/coreutils/compile
$(curdir)/findutils/compile += $(curdir)/coreutils/compile
$(curdir)/squashfs4/compile += $(curdir)/coreutils/compile
$(curdir)/util-linux/compile += $(curdir)/coreutils/compile
endif
ifeq ($(HOST_OS),Darwin)
tools-y += bash
else

View File

@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=automake
PKG_CPE_ID:=cpe:/a:gnu:automake
PKG_VERSION:=1.16.5
PKG_VERSION:=1.18.1
PKG_API_VERSION:=$(word 2,$(subst ., ,$(PKG_VERSION)))
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/automake
PKG_HASH:=07bd24ad08a64bc17250ce09ec56e921d6343903943e99ccf63bbf0705e34605
PKG_HASH:=63e585246d0fc8772dffdee0724f2f988146d1a3f1c756a3dc5cfbefa3c01915
include $(INCLUDE_DIR)/host-build.mk
@ -21,8 +21,7 @@ HOST_CONFIGURE_ARGS += \
--disable-silent-rules
HOST_CONFIGURE_VARS += \
PERL="/usr/bin/env perl" \
am_cv_prog_PERL_ithreads=no
PERL="/usr/bin/env perl"
define Host/Configure
(cd $(HOST_BUILD_DIR); $(AM_TOOL_PATHS) STAGING_DIR_HOST="" ./bootstrap)

View File

@ -1,6 +1,6 @@
--- a/lib/Automake/Config.in
+++ b/lib/Automake/Config.in
@@ -34,7 +34,7 @@ our $PACKAGE = '@PACKAGE@';
@@ -32,7 +32,7 @@ our $PACKAGE = '@PACKAGE@';
our $PACKAGE_BUGREPORT = '@PACKAGE_BUGREPORT@';
our $VERSION = '@VERSION@';
our $RELEASE_YEAR = '@RELEASE_YEAR@';
@ -11,9 +11,9 @@
# We need at least this version for CLONE support.
--- a/bin/aclocal.in
+++ b/bin/aclocal.in
@@ -23,9 +23,11 @@ use 5.006;
use strict;
use warnings FATAL => 'all';
@@ -21,9 +21,11 @@
use 5.006; use strict; use warnings;
+$^W = 1;
+
@ -24,22 +24,22 @@
unless $ENV{AUTOMAKE_UNINSTALLED};
}
@@ -65,8 +67,8 @@ $perl_threads = 0;
# ACLOCAL_PATH environment variable, and reset with the '--system-acdir'
# option.
@@ -63,8 +65,8 @@ $perl_threads = 0;
# --aclocal-path option/ACLOCAL_PATH environment variable, and reset
# with the '--system-acdir' option.
my @user_includes = ();
-my @automake_includes = ('@datadir@/aclocal-' . $APIVERSION);
-my @system_includes = ('@datadir@/aclocal');
+my @automake_includes = ($ENV{'STAGING_DIR_HOST'} ? $ENV{'STAGING_DIR_HOST'} . "/share/aclocal-$APIVERSION" : "@datadir@/aclocal-$APIVERSION");
+my @system_includes = ($ENV{'STAGING_DIR_HOST'} ? $ENV{'STAGING_DIR_HOST'} . '/share/aclocal' : '@datadir@/aclocal');
my $aclocal_path = '';
# Whether we should copy M4 file in $user_includes[0].
my $install = 0;
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -26,9 +26,11 @@ use 5.006;
use strict;
use warnings FATAL => 'all';
@@ -24,9 +24,11 @@ package Automake;
use 5.006; use strict; use warnings;
+$^W = 1;
+

View File

@ -1,6 +1,6 @@
--- a/bin/aclocal.in
+++ b/bin/aclocal.in
@@ -371,6 +371,12 @@ sub scan_m4_dirs ($$@)
@@ -370,6 +370,12 @@ sub scan_m4_dirs ($$@)
foreach my $m4dir (@dirlist)
{

View File

@ -1,15 +1,6 @@
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -4513,7 +4513,7 @@ sub handle_gettext ()
&& grep ($_ eq 'intl', @subdirs));
}
- require_file ($ac_gettext_location, GNU, 'ABOUT-NLS');
+ require_file ($ac_gettext_location, GNITS, 'ABOUT-NLS');
}
# Emit makefile footer.
@@ -5641,7 +5641,7 @@ sub check_gnu_standards ()
@@ -5700,7 +5700,7 @@ sub check_gnu_standards ()
# otherwise require non-.md.
my $required
= (! -f $file && -f "$file.md") ? "$file.md" : $file;
@ -18,7 +9,7 @@
}
# Accept one of these three licenses; default to COPYING.
@@ -5655,7 +5655,7 @@ sub check_gnu_standards ()
@@ -5714,7 +5714,7 @@ sub check_gnu_standards ()
last;
}
}

View File

@ -9,8 +9,8 @@ Subject: [PATCH] Allow other V values for verbosity
--- a/m4/silent.m4
+++ b/m4/silent.m4
@@ -43,7 +43,7 @@ else
fi])
@@ -53,7 +53,7 @@ case $enable_silent_rules in @%:@ (((
esac
if test $am_cv_make_support_nested_variables = yes; then
dnl Using '$V' instead of '$(V)' breaks IRIX make.
- AM_V='$(V)'

View File

@ -0,0 +1,34 @@
--- a/lib/Automake/Variable.pm
+++ b/lib/Automake/Variable.pm
@@ -1258,8 +1258,15 @@ sub output_variables ()
foreach my $var (@vars)
{
my $v = rvar $var;
+ # Output unconditional definitions before conditional ones.
+ if ($v->def (TRUE)) {
+ $res .= $v->output (TRUE)
+ if $v->rdef (TRUE)->owner == VAR_AUTOMAKE;
+ }
foreach my $cond ($v->conditions->conds)
{
+ # TRUE is handled already.
+ next if $cond->string eq "TRUE";
$res .= $v->output ($cond)
if $v->rdef ($cond)->owner == VAR_AUTOMAKE;
}
@@ -1269,8 +1276,15 @@ sub output_variables ()
foreach my $var (@vars)
{
my $v = rvar $var;
+ # Output unconditional definitions before conditional ones.
+ if ($v->def (TRUE)) {
+ $res .= $v->output (TRUE)
+ if $v->rdef (TRUE)->owner != VAR_AUTOMAKE;
+ }
foreach my $cond ($v->conditions->conds)
{
+ # TRUE is handled already.
+ next if $cond->string eq "TRUE";
$res .= $v->output ($cond)
if $v->rdef ($cond)->owner != VAR_AUTOMAKE;
}

View File

@ -0,0 +1,49 @@
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -4760,12 +4760,42 @@ sub handle_clean
if var ('CLEANFILES');
$clean_files{'$(DISTCLEANFILES)'} = DIST_CLEAN
if var ('DISTCLEANFILES');
- $clean_files{'$(MAINTAINERCLEANFILES)'} = MAINTAINER_CLEAN
- if var ('MAINTAINERCLEANFILES');
# Built sources are automatically removed by maintainer-clean.
- $clean_files{'$(BUILT_SOURCES)'} = MAINTAINER_CLEAN
- if var ('BUILT_SOURCES');
+ # For each defined condition of the maintainer-clean variable, append built sources
+ # and create an unconditional definition with built sources if not already defined.
+ # Then, for each definition of built sources without maintainer-clean defined, define it.
+ # Otherwise, if the variable is not user-defined, define it with built sources.
+ my $mcleanvar = var ('MAINTAINERCLEANFILES');
+ if ($mcleanvar) {
+ foreach my $rcond ($mcleanvar->conditions->conds)
+ {
+ if (! grep { $_ eq '$(BUILT_SOURCES)' } $mcleanvar->value_as_list ($rcond)) {
+ Automake::Variable::define ($mcleanvar->name, VAR_MAKEFILE, '+', $rcond,
+ '$(BUILT_SOURCES)', '', INTERNAL, VAR_ASIS)
+ if vardef ('BUILT_SOURCES', $rcond);
+ }
+ }
+ my $bsources = var ('BUILT_SOURCES');
+ if ($bsources) {
+ foreach my $rcond ($bsources->conditions->conds)
+ {
+ Automake::Variable::define ($mcleanvar->name, VAR_MAKEFILE, '', $rcond,
+ '$(BUILT_SOURCES)', '', INTERNAL, VAR_ASIS)
+ if ! vardef ($mcleanvar, $rcond);
+ }
+ if (! vardef ($mcleanvar, TRUE)) {
+ Automake::Variable::define ($mcleanvar->name, VAR_MAKEFILE, '', TRUE,
+ '$(BUILT_SOURCES)', '', INTERNAL, VAR_ASIS);
+ }
+ }
+ } else {
+ Automake::Variable::define ('MAINTAINERCLEANFILES', VAR_MAKEFILE, '', TRUE,
+ '$(BUILT_SOURCES)', '', INTERNAL, VAR_ASIS)
+ if var ('BUILT_SOURCES');
+ }
+ $clean_files{'$(MAINTAINERCLEANFILES)'} = MAINTAINER_CLEAN
+ if var ('MAINTAINERCLEANFILES');
# Compute a list of "rm"s to run for each target.
my %rms = (MOSTLY_CLEAN, [],

View File

@ -0,0 +1,28 @@
--- a/lib/am/clean.am
+++ b/lib/am/clean.am
@@ -39,7 +39,7 @@ distclean-generic:
## If you change distclean here, you probably also want to change
## maintainer-clean below.
distclean:
- -rm -f %MAKEFILE%
+ -touch %MAKEFILE%
maintainer-clean-am: maintainer-clean-generic distclean-am
maintainer-clean-generic:
@@ -51,7 +51,7 @@ maintainer-clean-generic:
## See comment for distclean.
maintainer-clean:
- -rm -f %MAKEFILE%
+ -touch %MAKEFILE%
.PHONY: clean mostlyclean distclean maintainer-clean \
clean-generic mostlyclean-generic distclean-generic maintainer-clean-generic
--- a/lib/am/libtool.am
+++ b/lib/am/libtool.am
@@ -25,4 +25,4 @@ clean-libtool:
?TOPDIR_P?distclean-am: distclean-libtool
?TOPDIR_P?distclean-libtool:
-?TOPDIR_P? -rm -f libtool config.lt
+?TOPDIR_P? -touch libtool config.lt

View File

@ -13,13 +13,14 @@ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=@GNU/bc
PKG_HASH:=515430115b3334c636317503460a0950dff79940aa3259ce2c1aa67c2881d023
PKG_FIXUP := autoreconf
PKG_CPE_ID:=cpe:/a:gnu:bc
PKG_SUBDIRS:=lib bc dc
include $(INCLUDE_DIR)/host-build.mk
define Host/Uninstall
-$(call Host/Compile/Default,uninstall)
-$(call Host/Compile/Default,uninstall SUBDIRS='lib bc dc')
endef
$(eval $(call HostBuild))

View File

@ -0,0 +1,18 @@
--- a/h/getopt.h
+++ b/h/getopt.h
@@ -135,15 +135,7 @@ struct option
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
-#ifdef __GNU_LIBRARY__
-/* Many other libraries have conflicting prototypes for getopt, with
- differences in the consts, in stdlib.h. To avoid compilation
- errors, only prototype getopt for the GNU C library. */
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
-#else /* not __GNU_LIBRARY__ */
-extern int getopt ();
-#endif /* __GNU_LIBRARY__ */
-
#ifndef __need_getopt
extern int getopt_long (int ___argc, char *const *___argv,
const char *__shortopts,

View File

@ -1,21 +0,0 @@
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = lib bc dc doc
+SUBDIRS = lib bc dc
MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \
stamp-h $(distdir).tar.gz h/number.h depcomp missing
--- a/Makefile.in
+++ b/Makefile.in
@@ -305,7 +305,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-SUBDIRS = lib bc dc doc
+SUBDIRS = lib bc dc
MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \
stamp-h $(distdir).tar.gz h/number.h depcomp missing

View File

@ -1,11 +0,0 @@
--- a/configure
+++ b/configure
@@ -5926,7 +5926,7 @@ case $bcle-$bcrl-$LEX in
?-?-flex)
LEX="flex -I -8" ;;
?-y-*)
- as_fn_error $? "readline works only with flex." "$LINENO" 5 ;;
+ : ;; # as_fn_error $? "readline works only with flex." "$LINENO" 5 ;;
esac
case $LEX-`uname -s` in

View File

@ -8,38 +8,42 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=coreutils
PKG_CPE_ID:=cpe:/a:gnu:coreutils
PKG_VERSION:=9.5
PKG_VERSION:=9.6
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/coreutils
PKG_HASH:=767ae6a22950ec42f3ba5f7c1de79dd27800ee8e9b8642da5dedb5974a1741e5
PKG_HASH:=2bec616375002c92c1ed5ead32a092b174fe44c14bc736d32e5961053b821d84
HOST_BUILD_PARALLEL := 1
PKG_PROGRAMS:=date readlink touch ln chown ginstall
PKG_PROGRAMS:=chown cp date ginstall ln readlink realpath rmdir seq stat touch
include $(INCLUDE_DIR)/host-build.mk
export GNULIB_SRCDIR:=$(HOST_GNULIB_SRCDIR)
HOST_GNULIB_SKIP := \
lib/nstrftime.c \
lib/fprintftime.c \
lib/fcntl.in.h \
lib/locale.in.h
lib/iconv_open-aix.gperf \
lib/iconv_open-hpux.gperf \
lib/iconv_open-irix.gperf \
lib/iconv_open-osf.gperf \
lib/iconv_open-solaris.gperf \
lib/iconv_open-zos.gperf
HOST_CONFIGURE_ARGS += \
--enable-install-program=$(subst $(space),$(comma),$(strip $(PKG_PROGRAMS)))
HOST_MAKE_FLAGS += \
$(AM_TOOL_PATHS_FAKE) \
$(AM_TOOL_PATHS) AUTOPOINT="$(TRUE)" GTKDOCIZE="$(TRUE)" \
am__CONFIG_DISTCLEAN_FILES= \
MAINTAINERCLEANFILES='$$$$(filter-out lib/iconv_open% %.texi,$$$$(BUILT_SOURCES))' \
PROGRAMS="$(patsubst %,src/%,$(PKG_PROGRAMS))" \
LIBRARIES= MANS= SUBDIRS=.
define Host/Bootstrap
( \
cd $(HOST_BUILD_DIR); \
$(AM_TOOL_PATHS_FAKE) \
$(AM_TOOL_PATHS) AUTOPOINT="$(TRUE)" GTKDOCIZE="$(TRUE)" \
./bootstrap \
--bootstrap-sync \
--force \
@ -58,17 +62,21 @@ define Host/Configure
$(if $(QUILT),$(call Host/Bootstrap))
$(foreach src,$(HOST_GNULIB_SKIP),mv -f $(HOST_BUILD_DIR)/$(src)~ $(HOST_BUILD_DIR)/$(src) || true; )
$(call Host/Configure/Default)
$(call Host/Uninstall)
$(call Host/Compile/Default,lib/config.h)
endef
define Host/Install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(patsubst %,$(HOST_BUILD_DIR)/src/%,$(PKG_PROGRAMS)) $(1)/bin/
ln -sf ginstall $(1)/bin/install
$(foreach prog,$(filter-out g%,$(PKG_PROGRAMS)),$(INSTALL_BIN) $(patsubst %,$(HOST_BUILD_DIR)/src/%,$(prog)) $(1)/bin/g$(prog); )
$(foreach prog,$(filter g%,$(PKG_PROGRAMS)),$(INSTALL_BIN) $(patsubst %,$(HOST_BUILD_DIR)/src/%,$(prog)) $(1)/bin/$(prog); )
$(foreach prog,$(filter-out g%,$(PKG_PROGRAMS)),g$(LN) g$(prog) $(1)/bin/$(prog); )
$(foreach prog,$(filter g%,$(PKG_PROGRAMS)),g$(LN) $(prog) $(1)/bin/$(patsubst g%,%,$(prog)); )
endef
define Host/Uninstall
rm -f $(STAGING_DIR_HOST)/bin/install
-$(call Host/Compile/Default,uninstall)
#$(call Host/Compile/Default,uninstall) # Removes necessary symlinks
-$(call Host/Compile/Default,maintainer-clean) # Clean bootstrap files from the release
endef
$(eval $(call HostBuild))

View File

@ -34,7 +34,7 @@
if [ ! "$inst_ver" ]; then
warn_ "Error: '$app' not found"
ret=1
@@ -1157,7 +1157,7 @@ autogen()
@@ -1205,7 +1205,7 @@ autogen()
# two just-pre-run programs.
# Import from gettext.
@ -43,3 +43,17 @@
grep '^[ ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \
with_gettext=no
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -354,11 +354,8 @@ gnulib_tool_option_extras="--tests-base=
buildreq="\
autoconf 2.64
automake 1.11.2
-autopoint 0.19.2
bison -
-gettext 0.19.2
git 1.4.4
-gperf -
gzip -
m4 -
makeinfo 6.1

View File

@ -3,12 +3,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=elfutils
PKG_VERSION:=0.191
PKG_RELEASE:=2
PKG_VERSION:=0.192
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:=https://sourceware.org/$(PKG_NAME)/ftp/$(PKG_VERSION)
PKG_HASH:=df76db71366d1d708365fc7a6c60ca48398f14367eb2b8954efc8897147ad871
PKG_HASH:=616099beae24aba11f9b63d86ca6cc8d566d968b802391334c91df54eab416b4
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=COPYING COPYING-GPLV2 COPYING-LGPLV3
@ -43,24 +43,49 @@ PKG_GNULIB_MODS = \
fallocate-posix \
fnmatch-gnu \
fts \
obstack \
obstack-printf-posix \
progname \
strchrnul \
tsearch
HOST_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/host-build.mk
export $(PKG_GNULIB_BASE)=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/.libs/$(PKG_GNULIB_BASE).a
export $(PKG_GNULIB_BASE)_exitfail=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-exitfail.o
export $(PKG_GNULIB_BASE)_fallocate-posix=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-posix_fallocate.o
export $(PKG_GNULIB_BASE)_mbszero=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-mbszero.o
export $(PKG_GNULIB_BASE)_obstack=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-obstack.o
export $(PKG_GNULIB_BASE)_obstack-printf=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-obstack_printf.o
export $(PKG_GNULIB_BASE)_printf-args=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-printf-args.o
export $(PKG_GNULIB_BASE)_printf-frexp=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-printf-frexp.o
export $(PKG_GNULIB_BASE)_printf-frexpl=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-printf-frexpl.o
export $(PKG_GNULIB_BASE)_printf-parse=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-printf-parse.o
export $(PKG_GNULIB_BASE)_tsearch=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-tsearch.o
export $(PKG_GNULIB_BASE)_vasnprintf=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-vasnprintf.o
export $(PKG_GNULIB_BASE)_xsize=$(HOST_BUILD_DIR)/$(PKG_GNULIB_BASE)/$(PKG_GNULIB_BASE)_la-xsize.o
HOST_MAKE_FLAGS += \
DEFAULT_INCLUDES='-I. -I$$$$(top_builddir) -I$$$$(top_srcdir)/$(PKG_GNULIB_BASE)' \
am__CONFIG_DISTCLEAN_FILES= \
DEFAULT_INCLUDES='-iquote . -I$$$$(top_builddir) -I$$$$(top_srcdir)/$(PKG_GNULIB_BASE)' \
AM_LDFLAGS='$$$$(STACK_USAGE_NO_ERROR)' \
LIBS+='$$$$(if $$$$(findstring $(lastword $(PKG_SUBDIRS)),$$$$(subdir)), $$$$($(PKG_GNULIB_BASE)))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_exitfail))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_fallocate-posix))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_mbszero))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_obstack))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_obstack-printf))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_printf-args))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_printf-frexp))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_printf-frexpl))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_printf-parse))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_tsearch))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_vasnprintf))' \
LIBS+='$$$$(wildcard $$$$($(PKG_GNULIB_BASE)_xsize))' \
REPLACE_FCNTL=0 REPLACE_FREE=0 REPLACE_FSTAT=0 REPLACE_OPEN=0 \
REPLACE_OBSTACK=0 REPLACE_OBSTACK_PRINTF=0 \
bin_PROGRAMS='$(PKG_PROGRAMS)' EXEEXT=
HOST_CPPFLAGS += "'-I$$$$(top_srcdir)/lib'"
@ -72,6 +97,7 @@ endif
HOST_CFLAGS += -Wno-error -fPIC -std=gnu17
HOST_CONFIGURE_ARGS += \
--enable-maintainer-mode \
--without-libintl-prefix \
--without-libiconv-prefix \
--disable-debuginfod \
@ -96,8 +122,14 @@ HOST_CONFIGURE_VARS += \
Hooks/HostConfigure/Pre := Host/Gnulib/Prepare $(Hooks/HostConfigure/Pre)
Hooks/HostCompile/Pre := Host/Gnulib/Compile $(Hooks/HostCompile/Pre)
define Host/Configure
$(call Host/Configure/Default)
$(call Host/Uninstall)
endef
define Host/Uninstall
-$(call Host/Compile/Default,uninstall)
-$(call Host/Compile/Default,maintainer-clean) # Clean bootstrap files from the release
endef
$(eval $(call HostBuild))

View File

@ -0,0 +1,12 @@
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,8 @@ DEFS += $(YYDEBUG) -DDEBUGPRED=@DEBUGPRE
-DSRCDIR=\"$(shell cd $(srcdir);pwd)\" -DOBJDIR=\"$(shell pwd)\"
DEFAULT_INCLUDES =
-AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
+AM_CPPFLAGS = -iquote . -iquote $(srcdir) -I$(top_srcdir)/lib \
+ -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
-I$(srcdir)/../libdw -I$(srcdir)/../libdwelf \
-I$(srcdir)/../libdwfl -I$(srcdir)/../libasm -I../debuginfod

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,230 @@
In mips64 little-endian, r_info consists of four byte fields(contains
three reloc types) and a 32-bit symbol index. In order to adapt
GELF_R_SYM and GELF_R_TYPE, need convert raw data to get correct symbol
index and type.
libelf/elf_getdata.c: Some eu-utils use read-mmap method to map file,
so we need to malloc and memcpy raw data to avoid segment fault. After
modification, the correct value are saved in the malloced memory not in
process address space.
libelf/elf_updata.c: Because we converted the relocation info in mips
order when we call elf_getdata.c, so we need to convert the modified data
in original order bits before writing the data to the file.
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
---
libelf/elf_getdata.c | 132 ++++++++++++++++++++++++++++++++++++++++++-
libelf/elf_update.c | 53 +++++++++++++++++
2 files changed, 183 insertions(+), 2 deletions(-)
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -135,6 +135,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int
/* Convert the data in the current section. */
static void
+convert_data_for_mips64el (Elf_Scn *scn, int eclass,
+ int data, size_t size, Elf_Type type)
+{
+ /* Do we need to convert the data and/or adjust for alignment? */
+ if (data == MY_ELFDATA || type == ELF_T_BYTE)
+ {
+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert
+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so
+ we need to malloc and memcpy raw data to avoid segment fault. After modification,
+ the correct value are saved in the malloced memory not in process address space. */
+ scn->data_base = malloc (size);
+ if (scn->data_base == NULL)
+ {
+ __libelf_seterrno (ELF_E_NOMEM);
+ return;
+ }
+
+ /* The copy will be appropriately aligned for direct access. */
+ memcpy (scn->data_base, scn->rawdata_base, size);
+ }
+ else
+ {
+ xfct_t fp;
+
+ scn->data_base = malloc (size);
+ if (scn->data_base == NULL)
+ {
+ __libelf_seterrno (ELF_E_NOMEM);
+ return;
+ }
+
+ /* Make sure the source is correctly aligned for the conversion
+ function to directly access the data elements. */
+ char *rawdata_source;
+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert
+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so
+ we need to malloc and memcpy raw data to avoid segment fault. After modification,
+ the correct value are saved in the malloced memory not in process address space. */
+ rawdata_source = malloc (size);
+ if (rawdata_source == NULL)
+ {
+ __libelf_seterrno (ELF_E_NOMEM);
+ return;
+ }
+
+ /* The copy will be appropriately aligned for direct access. */
+ memcpy (rawdata_source, scn->rawdata_base, size);
+
+ /* Get the conversion function. */
+ fp = __elf_xfctstom[eclass - 1][type];
+
+ fp (scn->data_base, rawdata_source, size, 0);
+
+ if (rawdata_source != scn->rawdata_base)
+ free (rawdata_source);
+ }
+
+ scn->data_list.data.d.d_buf = scn->data_base;
+ scn->data_list.data.d.d_size = size;
+ scn->data_list.data.d.d_type = type;
+ scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
+ scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
+ scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
+
+ scn->data_list.data.s = scn;
+
+ /* In mips64 little-endian, r_info consists of four byte fields(contains
+ three reloc types) and a 32-bit symbol index. In order to adapt
+ GELF_R_SYM and GELF_R_TYPE, need to convert r_info to get correct symbol
+ index and type. */
+ /* references:
+ https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
+ Page40 && Page41 */
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr->sh_type == SHT_REL)
+ {
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT);
+ int nentries = shdr->sh_size / sh_entsize;
+ for (int cnt = 0; cnt < nentries; ++cnt)
+ {
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d;
+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt];
+ Elf64_Xword info = value->r_info;
+ value->r_info = (((info & 0xffffffff) << 32)
+ | ((info >> 56) & 0xff)
+ | ((info >> 40) & 0xff00)
+ | ((info >> 24) & 0xff0000)
+ | ((info >> 8) & 0xff000000));
+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value;
+ }
+ }
+ else if (shdr->sh_type == SHT_RELA)
+ {
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT);
+ int nentries = shdr->sh_size / sh_entsize;
+ for (int cnt = 0; cnt < nentries; cnt++)
+ {
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d;
+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt];
+ Elf64_Xword info = value->r_info;
+ value->r_info = (((info & 0xffffffff) << 32)
+ | ((info >> 56) & 0xff)
+ | ((info >> 40) & 0xff00)
+ | ((info >> 24) & 0xff0000)
+ | ((info >> 8) & 0xff000000));
+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value;
+ }
+ }
+}
+
+/* Convert the data in the current section. */
+static void
convert_data (Elf_Scn *scn, int eclass,
int data, size_t size, Elf_Type type)
{
@@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn *
return;
}
- /* Convert according to the version and the type. */
- convert_data (scn, elf->class,
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem);
+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) &&
+ scn->elf->class == ELFCLASS64 && ehdr != NULL &&
+ ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+ convert_data_for_mips64el (scn, elf->class,
+ (elf->class == ELFCLASS32
+ || (offsetof (struct Elf, state.elf32.ehdr)
+ == offsetof (struct Elf, state.elf64.ehdr))
+ ? elf->state.elf32.ehdr->e_ident[EI_DATA]
+ : elf->state.elf64.ehdr->e_ident[EI_DATA]),
+ scn->rawdata.d.d_size, scn->rawdata.d.d_type);
+ else
+ /* Convert according to the version and the type. */
+ convert_data (scn, elf->class,
(elf->class == ELFCLASS32
|| (offsetof (struct Elf, state.elf32.ehdr)
== offsetof (struct Elf, state.elf64.ehdr))
--- a/libelf/elf_update.c
+++ b/libelf/elf_update.c
@@ -228,7 +228,60 @@ elf_update (Elf *elf, Elf_Cmd cmd)
size = -1;
}
else
+ {
+ /* Because we converted the relocation info in mips order when we call elf_getdata.c,
+ so we need to convert the modified data in original order bits before writing the
+ data to the file. */
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem);
+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) &&
+ scn->elf->class == ELFCLASS64 &&
+ ehdr != NULL && ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+ {
+ Elf_Data *d = elf_getdata (scn, NULL);
+ if (shdr->sh_type == SHT_REL)
+ {
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT);
+ int nentries = shdr->sh_size / sh_entsize;
+ for (int cnt = 0; cnt < nentries; ++cnt)
+ {
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d;
+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt];
+ Elf64_Xword info = value->r_info;
+ value->r_info = (info >> 32
+ | ((info << 56) & 0xff00000000000000)
+ | ((info << 40) & 0xff000000000000)
+ | ((info << 24) & 0xff0000000000)
+ | ((info << 8) & 0xff00000000));
+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value;
+ }
+ }
+ else if (shdr->sh_type == SHT_RELA)
+ {
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT);
+ int nentries = shdr->sh_size / sh_entsize;
+ for (int cnt = 0; cnt < nentries; cnt++)
+ {
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d;
+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt];
+ Elf64_Xword info = value->r_info;
+ value->r_info = (info >> 32
+ | ((info << 56) & 0xff00000000000000)
+ | ((info << 40) & 0xff000000000000)
+ | ((info << 24) & 0xff0000000000)
+ | ((info << 8) & 0xff00000000));
+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value;
+ }
+ }
+ }
+ }
size = write_file (elf, size, change_bo, shnum);
+ }
}
out:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
The errors were:
$ src/elflint --gnu src/nm
section [ 2] '.MIPS.options' contains unknown flag(s) 0x8000000
section [ 7] '.dynsym': symbol 165 (_DYNAMIC_LINKING): non-local section symbol
section [24] '.got' contains invalid processor-specific flag(s) 0x10000000
section [25] '.sdata' contains invalid processor-specific flag(s) 0x10000000
section [29] '.debug_aranges' has wrong type: expected PROGBITS, is MIPS_DWARF
section [30] '.debug_info' has wrong type: expected PROGBITS, is MIPS_DWARF
section [31] '.debug_abbrev' has wrong type: expected PROGBITS, is MIPS_DWARF
section [32] '.debug_line' has wrong type: expected PROGBITS, is MIPS_DWARF
section [33] '.debug_frame' has wrong type: expected PROGBITS, is MIPS_DWARF
section [34] '.debug_str' has wrong type: expected PROGBITS, is MIPS_DWARF
section [35] '.debug_loc' has wrong type: expected PROGBITS, is MIPS_DWARF
section [36] '.debug_ranges' has wrong type: expected PROGBITS, is MIPS_DWARF
section [38] '.symtab': symbol 785 (_gp): st_value out of bounds
section [38] '.symtab': symbol 910 (_fbss): st_value out of bounds
section [38] '.symtab': symbol 1051 (_DYNAMIC_LINKING): non-local section symbol
After fixing:
$ src/elflint --gnu src/nm
No errors
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
---
backends/mips_init.c | 3 +++
backends/mips_symbol.c | 37 +++++++++++++++++++++++++++++++++++++
src/elflint.c | 26 +++++++++++++++++++++-----
3 files changed, 61 insertions(+), 5 deletions(-)
--- a/backends/mips_init.c
+++ b/backends/mips_init.c
@@ -51,10 +51,13 @@ mips_init (Elf *elf __attribute__ ((unus
HOOK (eh, section_type_name);
HOOK (eh, machine_flag_check);
HOOK (eh, machine_flag_name);
+ HOOK (eh, machine_section_flag_check);
HOOK (eh, segment_type_name);
HOOK (eh, dynamic_tag_check);
HOOK (eh, dynamic_tag_name);
HOOK (eh, check_object_attribute);
+ HOOK (eh, check_special_symbol);
+ HOOK (eh, check_reloc_target_type);
HOOK (eh, set_initial_registers_tid);
HOOK (eh, abi_cfi);
HOOK (eh, unwind);
--- a/backends/mips_symbol.c
+++ b/backends/mips_symbol.c
@@ -158,6 +158,43 @@ mips_section_type_name (int type,
return NULL;
}
+bool
+mips_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type)
+{
+ return (sh_type == SHT_MIPS_DWARF);
+}
+
+/* Check whether given symbol's st_value and st_size are OK despite failing
+ normal checks. */
+bool
+mips_check_special_symbol (Elf *elf,
+ const GElf_Sym *sym __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ const GElf_Shdr *destshdr)
+{
+ size_t shstrndx;
+ if (elf_getshdrstrndx (elf, &shstrndx) != 0)
+ return false;
+ const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name);
+ if (sname == NULL)
+ return false;
+ return (strcmp (sname, ".got") == 0 || strcmp (sname, ".bss") == 0);
+}
+
+/* Check whether SHF_MASKPROC flags are valid. */
+bool
+mips_machine_section_flag_check (GElf_Xword sh_flags)
+{
+ return ((sh_flags &~ (SHF_MIPS_GPREL |
+ SHF_MIPS_MERGE |
+ SHF_MIPS_ADDR |
+ SHF_MIPS_STRINGS |
+ SHF_MIPS_NOSTRIP |
+ SHF_MIPS_LOCAL |
+ SHF_MIPS_NAMES |
+ SHF_MIPS_NODUPE)) == 0);
+}
+
/* Check whether machine flags are valid. */
bool
mips_machine_flag_check (GElf_Word flags)
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -936,7 +936,9 @@ section [%2d] '%s': symbol %zu (%s): non
}
if (GELF_ST_TYPE (sym->st_info) == STT_SECTION
- && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && GELF_ST_BIND (sym->st_info) != STB_LOCAL
+ && ehdr->e_machine != EM_MIPS
+ && strcmp (name, "_DYNAMIC_LINKING") != 0)
ERROR (_("\
section [%2d] '%s': symbol %zu (%s): non-local section symbol\n"),
idx, section_name (ebl, idx), cnt, name);
@@ -3829,6 +3831,10 @@ cannot get section header for section [%
&& ebl_bss_plt_p (ebl))
good_type = SHT_NOBITS;
+ if (ehdr->e_machine == EM_MIPS
+ && (strstr(special_sections[s].name, ".debug") != NULL))
+ good_type = SHT_MIPS_DWARF;
+
/* In a debuginfo file, any normal section can be SHT_NOBITS.
This is only invalid for DWARF sections and .shstrtab. */
if (shdr->sh_type != good_type
@@ -3989,12 +3995,21 @@ section [%2zu] '%s': size not multiple o
ERROR (_("section [%2zu] '%s'"
" contains invalid processor-specific flag(s)"
" %#" PRIx64 "\n"),
- cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
sh_flags &= ~(GElf_Xword) SHF_MASKPROC;
}
if (sh_flags & SHF_MASKOS)
- if (gnuld)
- sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN;
+ {
+ if (gnuld)
+ sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN;
+ if (!ebl_machine_section_flag_check (ebl,
+ sh_flags & SHF_MASKOS))
+ ERROR (_("section [%2zu] '%s'"
+ " contains invalid os-specific flag(s)"
+ " %#" PRIx64 "\n"),
+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKOS);
+ sh_flags &= ~(GElf_Xword) SHF_MASKOS;
+ }
if (sh_flags != 0)
ERROR (_("section [%2zu] '%s' contains unknown flag(s)"
" %#" PRIx64 "\n"),
@@ -4060,6 +4075,7 @@ section [%2zu] '%s': merge flag set but
switch (shdr->sh_type)
{
case SHT_PROGBITS:
+ case SHT_MIPS_DWARF:
break;
case SHT_NOBITS:
@@ -4717,7 +4733,7 @@ program header offset in ELF header and
if (shdr != NULL
&& ((is_debuginfo && shdr->sh_type == SHT_NOBITS)
|| (! is_debuginfo
- && (shdr->sh_type == SHT_PROGBITS
+ && (is_debug_section_type(shdr->sh_type)
|| shdr->sh_type == SHT_X86_64_UNWIND)))
&& elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL
&& ! strcmp (".eh_frame_hdr",

View File

@ -23,7 +23,7 @@
# Only available since automake 1.12
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
AC_CHECK_TOOL([READELF], [readelf])
@@ -635,6 +639,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([])],
@@ -646,6 +650,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([])],
CFLAGS="$old_CFLAGS"])
AS_IF([test "x$ac_cv_fno_addrsig" = "xyes"], CFLAGS="$CFLAGS -fno-addrsig")
@ -34,9 +34,9 @@
LIBS="$saved_LIBS"
--- a/lib/eu-config.h
+++ b/lib/eu-config.h
@@ -59,14 +59,19 @@
# define once(once_control, init_routine) init_routine()
#endif /* USE_LOCKS */
@@ -31,14 +31,19 @@
#include "locks.h"
-#include <libintl.h>
+#include <gettext.h>
@ -55,7 +55,7 @@
#ifdef __i386__
# define internal_function __attribute__ ((regparm (3), stdcall))
@@ -77,7 +82,7 @@
@@ -49,7 +54,7 @@
#define internal_strong_alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((alias (#name))) internal_function;
@ -64,7 +64,7 @@
#define attribute_hidden \
__attribute__ ((visibility ("hidden")))
#else
@@ -166,7 +171,7 @@ asm (".section predict_data, \"aw\"; .pr
@@ -138,7 +143,7 @@ asm (".section predict_data, \"aw\"; .pr
#endif
/* Avoid PLT entries. */
@ -203,7 +203,7 @@
+#include <libeu.h>
#include <libdw.h>
#include <dwarf.h>
#include "eu-search.h"
--- a/config/libdebuginfod.pc.in
+++ b/config/libdebuginfod.pc.in
@@ -8,5 +8,5 @@ Description: elfutils library to query d
@ -235,19 +235,9 @@
Cflags: -I${includedir}
Requires.private: zlib @LIBZSTD@
--- a/lib/next_prime.c
+++ b/lib/next_prime.c
@@ -27,6 +27,7 @@
the GNU Lesser General Public License along with this program. If
not, see <http://www.gnu.org/licenses/>. */
+#include <config.h>
#include <stddef.h>
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -200,8 +200,6 @@ static bool default_object_note (const c
@@ -202,8 +202,6 @@ static bool default_object_note (const c
uint32_t descsz, const char *desc);
static bool default_debugscn_p (const char *name);
static bool default_copy_reloc_p (int reloc);
@ -256,7 +246,7 @@
static bool default_check_special_symbol (Elf *elf,
const GElf_Sym *sym,
const char *name,
@@ -253,8 +251,8 @@ fill_defaults (Ebl *result)
@@ -255,8 +253,8 @@ fill_defaults (Ebl *result)
result->object_note = default_object_note;
result->debugscn_p = default_debugscn_p;
result->copy_reloc_p = default_copy_reloc_p;
@ -267,7 +257,7 @@
result->check_special_symbol = default_check_special_symbol;
result->data_marker_symbol = default_data_marker_symbol;
result->check_st_other_bits = default_check_st_other_bits;
@@ -636,8 +634,6 @@ default_copy_reloc_p (int reloc __attrib
@@ -638,8 +636,6 @@ default_copy_reloc_p (int reloc __attrib
{
return false;
}
@ -276,25 +266,3 @@
static bool
default_check_special_symbol (Elf *elf __attribute__ ((unused)),
--- a/src/srcfiles.cxx
+++ b/src/srcfiles.cxx
@@ -78,7 +78,9 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = print_ve
/* Bug report address. */
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
+#ifdef HAVE_LIBARCHIVE
constexpr size_t BUFFER_SIZE = 8192;
+#endif
/* Definitions of arguments for argp functions. */
static const struct argp_option options[] =
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -92,6 +92,7 @@ strings_LDADD = $(libelf) $(libeu) $(arg
ar_LDADD = libar.a $(libelf) $(libeu) $(argp_LDADD) $(obstack_LIBS)
unstrip_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD)
stack_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) $(demanglelib)
+EXTRA_stack_DEPENDENCIES = $(if $(findstring srcfiles,$(bin_PROGRAMS)),$(srcfiles_OBJECTS))
elfcompress_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD)
elfclassify_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD)
srcfiles_SOURCES = srcfiles.cxx

View File

@ -9,7 +9,7 @@
AC_CACHE_CHECK([whether gcc supports __attribute__((visibility()))],
ac_cv_visibility, [dnl
save_CFLAGS="$CFLAGS"
@@ -419,7 +421,10 @@ AS_HELP_STRING([--enable-install-elfh],[
@@ -423,7 +425,10 @@ AS_HELP_STRING([--enable-install-elfh],[
AM_CONDITIONAL(INSTALL_ELFH, test "$install_elfh" = yes)
AM_CONDITIONAL(BUILD_STATIC, [dnl
@ -64,7 +64,7 @@
include_HEADERS = dwarf.h
pkginclude_HEADERS = libdw.h known-dwarf.h
@@ -121,11 +123,13 @@ libdw.so: $(srcdir)/libdw.map $(libdw_so
@@ -120,11 +122,13 @@ libdw.so: $(srcdir)/libdw.map $(libdw_so
@$(textrel_check)
$(AM_V_at)ln -fs $@ $@.$(VERSION)
@ -78,7 +78,7 @@
uninstall: uninstall-am
rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
@@ -148,6 +152,10 @@ libdw_a_LIBADD += $(addprefix ../backend
@@ -147,6 +151,10 @@ libdw_a_LIBADD += $(addprefix ../backend
libcpu_objects = $(shell $(AR) t ../libcpu/libcpu.a)
libdw_a_LIBADD += $(addprefix ../libcpu/,$(libcpu_objects))
@ -132,7 +132,7 @@
libdebuginfod_a_SOURCES = debuginfod-client.c
libdebuginfod_pic_a_SOURCES = debuginfod-client.c
@@ -111,12 +113,16 @@ $(LIBDEBUGINFOD_SONAME): $(srcdir)/libde
@@ -111,12 +113,17 @@ $(LIBDEBUGINFOD_SONAME): $(srcdir)/libde
libdebuginfod.so: $(LIBDEBUGINFOD_SONAME)
ln -fs $< $@
@ -146,9 +146,10 @@
+else
+libdebuginfod_a_LIBADD = $(foreach dep,$(wildcard $(libdebuginfod_so_LDLIBS:.so=.a)) $(LIBS:.so=.a),$(if $(findstring a,$(suffix $(dep))),$(addprefix $(dir $(dep)),$(shell cat $(basename $(dep)).manifest)),$(dep)))
+endif
+
uninstall: uninstall-am
rm -f $(DESTDIR)$(libdir)/libdebuginfod-$(PACKAGE_VERSION).so
rm -f $(DESTDIR)$(libdir)/$(LIBDEBUGINFOD_SONAME)
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,7 +50,7 @@ check_PROGRAMS = arextract arsymtest new
@ -158,9 +159,9 @@
- buildid deleted deleted-lib.so aggregate_size peel_type \
+ buildid aggregate_size peel_type \
vdsosyms \
getsrc_die strptr newdata elfstrtab dwfl-proc-attach \
elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
@@ -180,7 +180,7 @@ TESTS = run-arextract.sh run-arsymtest.s
getsrc_die strptr newdata newzdata \
elfstrtab dwfl-proc-attach \
@@ -181,7 +181,7 @@ TESTS = run-arextract.sh run-arsymtest.s
run-readelf-addr.sh run-readelf-str.sh \
run-readelf-multi-noline.sh \
run-readelf-types.sh \
@ -168,10 +169,10 @@
+ run-readelf-dwz-multi.sh run-allfcts-multi.sh \
run-linkmap-cut.sh run-aggregate-size.sh run-peel-type.sh \
vdsosyms run-readelf-A.sh \
run-getsrc-die.sh run-strptr.sh newdata elfstrtab dwfl-proc-attach \
@@ -284,6 +284,11 @@ funcretval_test__11_SOURCES = funcretval
TESTS += run-funcretval++11.sh
endif
run-getsrc-die.sh run-strptr.sh newdata newzdata \
@@ -298,6 +298,11 @@ check_PROGRAMS += funcretval_test_struct
funcretval_test_struct_SOURCES = funcretval_test_struct.c
TESTS += run-funcretval-struct-native.sh
+if BUILD_SHARED
+check_PROGRAMS += deleted deleted-lib.so

View File

@ -1,6 +1,6 @@
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -137,19 +137,19 @@ uninstall: uninstall-am
@@ -136,19 +136,19 @@ uninstall: uninstall-am
rm -f $(DESTDIR)$(libdir)/libdw.so
rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
@ -25,7 +25,7 @@
libdw_a_LIBADD += $(addprefix ../libcpu/,$(libcpu_objects))
if !BUILD_SHARED
@@ -161,4 +161,9 @@ noinst_HEADERS = libdwP.h memory-access.
@@ -160,5 +160,10 @@ noinst_HEADERS = libdwP.h memory-access.
EXTRA_DIST = libdw.map
@ -36,9 +36,10 @@
+ echo $^ > $@
+
+MOSTLYCLEANFILES = $(am_libdw_pic_a_OBJECTS) $(EXTRA_libdw_a_DEPENDENCIES) libdw.so libdw.so.$(VERSION)
MAINTAINERCLEANFILES = $(srcdir)/known-dwarf.h
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -93,4 +93,10 @@ am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_S
@@ -94,4 +94,10 @@ am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_S
noinst_HEADERS = libdwflP.h
@ -77,7 +78,7 @@
+MOSTLYCLEANFILES = $(am_libebl_pic_a_OBJECTS) $(EXTRA_libebl_a_DEPENDENCIES)
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -119,4 +119,9 @@ am_libebl_backends_pic_a_OBJECTS = $(lib
@@ -122,4 +122,9 @@ am_libebl_backends_pic_a_OBJECTS = $(lib
noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c x86_corenote.c
EXTRA_DIST = $(modules:=_reloc.def)
@ -118,9 +119,9 @@
CLEANFILES += $(am_libelf_pic_a_OBJECTS) libelf.so libelf.so.$(VERSION)
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -41,3 +41,10 @@ noinst_HEADERS = fixedsizehash.h libeu.h
eu-config.h color.h printversion.h bpf.h \
atomics.h stdatomic-fbsd.h dynamicsizehash_concurrent.h
@@ -42,3 +42,10 @@ noinst_HEADERS = fixedsizehash.h libeu.h
atomics.h stdatomic-fbsd.h dynamicsizehash_concurrent.h \
eu-search.h locks.h
EXTRA_DIST = dynamicsizehash.c dynamicsizehash_concurrent.c
+
+EXTRA_libeu_a_DEPENDENCIES = libeu.manifest

View File

@ -2,11 +2,11 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gnulib
PKG_CPE_ID:=cpe:/a:gnu:$(PKG_NAME)
PKG_VERSION:=c99c8d491850dc3a6e0b8604a2729d8bc5c0eff1# # stable-202401
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://git.savannah.gnu.org/cgit/$(PKG_NAME).git/snapshot
PKG_HASH:=8e6f4a907d9677b55fd452e1340a3e030a6f530b138d420c11975da33f086b1e
PKG_SOURCE_URL=git://git.git.savannah.gnu.org/$(PKG_NAME).git
PKG_SOURCE_DATE:=2025-07-01
PKG_SOURCE_VERSION:=a3151d456d6919c9066b54dc6f680452168165cf# # stable-202501
PKG_MIRROR_HASH:=b695d96e915ecd6c4551436f417cb2c0879aef4ef6318721c8d5cc86cb44ba9d
include $(INCLUDE_DIR)/host-build.mk
@ -14,14 +14,14 @@ define Host/Configure
endef
define Host/Install
$(call Host/Uninstall)
$(INSTALL_DIR) $(1)/share/aclocal
$(INSTALL_DATA) $(HOST_BUILD_DIR)/m4/*.m4 $(1)/share/aclocal/
$(INSTALL_DIR) $(1)/share/gnulib
$(CP) $(HOST_BUILD_DIR)/* $(1)/share/gnulib/
$(CP) $(HOST_BUILD_DIR)/ $(1)/share/gnulib/
ln -sf ../share/gnulib/gnulib-tool $(STAGING_DIR_HOST)/bin/gnulib-tool
endef
define Host/Clean
define Host/Uninstall
rm -rf $(STAGING_DIR_HOST)/bin/gnulib-tool $(STAGING_DIR_HOST)/share/gnulib
endef

View File

@ -43,7 +43,7 @@
if [ ! "$inst_ver" ]; then
warn_ "Error: '$app' not found"
ret=1
@@ -1157,7 +1157,7 @@ autogen()
@@ -1205,7 +1205,7 @@ autogen()
# two just-pre-run programs.
# Import from gettext.

View File

@ -1,6 +1,6 @@
--- a/gnulib-tool
+++ b/gnulib-tool
@@ -346,6 +346,34 @@ Options for --import, --add/remove-impor
--- a/gnulib-tool.sh
+++ b/gnulib-tool.sh
@@ -344,6 +344,34 @@ Options for --import, --add/remove-impor
Report bugs to <bug-gnulib@gnu.org>."
}
@ -35,7 +35,7 @@
# func_version
# outputs to stdout the --version message.
func_version ()
@@ -1620,6 +1648,9 @@ func_determine_path_separator
@@ -1666,6 +1694,9 @@ func_determine_path_separator
fi
case "$autoconf_minversion" in
1.* | 2.[0-5]* | 2.6[0-3]*)

View File

@ -0,0 +1,47 @@
--- a/pygnulib/functions.py
+++ b/pygnulib/functions.py
@@ -16,6 +16,8 @@
from __future__ import annotations
import os.path
+import re
+import subprocess as sp
from .constants import substart
from .GLConfig import GLConfig
@@ -50,3 +52,15 @@ def rewrite_file_name(file_name: str, co
else: # file is not a special file
result = file_name
return os.path.normpath(result)
+
+def get_version(app: str) -> str:
+ result = sp.run([app, '--version'], capture_output=True, text=True)
+ version = re.sub(r".*[v ]([0-9])", r"\1", result.stdout)
+ version_lines = [line for line in version.splitlines() if re.search(r"^[0-9]", line)]
+ version = '\n'.join(version_lines) + "\n"
+ version = re.sub(r"[^.a-z0-9-\n].*", r"", version)
+ version = re.sub(r"^([0-9]*)[a-z-].*", r"\1", version, 1)
+ version = re.sub(r"\.0*([1-9])", r".\1", version)
+ version_lines = [line for line in version.splitlines() if line.strip()]
+ version = ''.join(version_lines[0]) + "\n"
+ return version.strip()
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -40,6 +40,7 @@ from .constants import (
rmtree,
)
from .functions import rewrite_file_name
+from .functions import get_version
from .GLError import GLError
from .GLConfig import GLConfig
from .GLModuleSystem import GLModuleTable
@@ -125,7 +126,8 @@ class GLImport:
for version in versions })
self.config.setAutoconfVersion(version)
if version < 2.64:
- raise GLError(4, version)
+ # If the version of autoconf in use is high enough, do not error.
+ if float(get_version('autoconf')) < 2.64: raise GLError(4, version)
# Get other cached variables.
path = joinpath(self.config['m4base'], 'gnulib-cache.m4')

View File

@ -107,7 +107,7 @@
+#endif /* defined(_LIBC) || GNULIB_defined_tdestroy */
--- a/m4/search_h.m4
+++ b/m4/search_h.m4
@@ -39,7 +39,7 @@ AC_DEFUN_ONCE([gl_SEARCH_H],
@@ -41,7 +41,7 @@ AC_DEFUN_ONCE([gl_SEARCH_H],
dnl Check for declarations of anything we want to poison if the
dnl corresponding gnulib module is not in use.
gl_WARN_ON_USE_PREPARE([[#include <search.h>
@ -116,7 +116,7 @@
AC_REQUIRE([AC_C_RESTRICT])
])
@@ -75,8 +75,10 @@ AC_DEFUN([gl_SEARCH_H_DEFAULTS],
@@ -77,8 +77,10 @@ AC_DEFUN([gl_SEARCH_H_DEFAULTS],
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LFIND], [1])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LSEARCH], [1])
dnl Assume proper GNU behavior unless another module says otherwise.
@ -133,7 +133,7 @@
])
--- a/m4/tsearch.m4
+++ b/m4/tsearch.m4
@@ -9,6 +9,7 @@ AC_DEFUN([gl_FUNC_TSEARCH],
@@ -11,6 +11,7 @@ AC_DEFUN([gl_FUNC_TSEARCH],
AC_REQUIRE([gl_SEARCH_H_DEFAULTS])
gl_CHECK_FUNCS_ANDROID([tsearch], [[#include <search.h>]])
gl_CHECK_FUNCS_ANDROID([twalk], [[#include <search.h>]])
@ -141,7 +141,7 @@
if test $ac_cv_func_tsearch = yes; then
dnl On OpenBSD 4.0, the return value of tdelete() is incorrect.
AC_REQUIRE([AC_PROG_CC])
@@ -50,6 +51,7 @@ main ()
@@ -52,6 +53,7 @@ main ()
*no)
REPLACE_TSEARCH=1
REPLACE_TWALK=1
@ -149,7 +149,7 @@
;;
esac
else
@@ -64,6 +66,12 @@ main ()
@@ -66,6 +68,12 @@ main ()
future*) REPLACE_TWALK=1 ;;
esac
fi
@ -162,8 +162,8 @@
])
# Prerequisites of lib/tsearch.c.
--- a/modules/search
+++ b/modules/search
--- a/modules/search-h
+++ b/modules/search-h
@@ -37,8 +37,10 @@ search.h: search.in.h $(top_builddir)/co
-e 's/@''GNULIB_MDA_LSEARCH''@/$(GNULIB_MDA_LSEARCH)/g' \
-e 's|@''HAVE_TSEARCH''@|$(HAVE_TSEARCH)|g' \
@ -177,7 +177,7 @@
-e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
--- a/modules/tsearch
+++ b/modules/tsearch
@@ -11,7 +11,12 @@ search
@@ -11,7 +11,12 @@ search-h
configure.ac:
gl_FUNC_TSEARCH
gl_CONDITIONAL([GL_COND_OBJ_TSEARCH],

View File

@ -1,6 +1,6 @@
--- a/lib/ialloc.h
+++ b/lib/ialloc.h
@@ -106,6 +106,8 @@ icalloc (idx_t n, idx_t s)
@@ -91,6 +91,8 @@ icalloc (idx_t n, idx_t s)
return calloc (n, s);
}
@ -9,8 +9,8 @@
/* ireallocarray (ptr, num, size) is like reallocarray (ptr, num, size).
It returns a non-NULL pointer to num * size bytes of memory.
Upon failure, it returns NULL with errno set. */
@@ -131,6 +133,8 @@ ireallocarray (void *p, idx_t n, idx_t s
return _gl_alloc_nomem ();
@@ -102,6 +104,8 @@ ireallocarray (void *p, idx_t n, idx_t s
: _gl_alloc_nomem ());
}
+#endif /* GNULIB_REALLOCARRAY */
@ -21,7 +21,7 @@
--- a/lib/xmalloc.c
+++ b/lib/xmalloc.c
@@ -51,12 +51,16 @@ ximalloc (idx_t s)
return nonnull (imalloc (s));
return check_nonnull (imalloc (s));
}
+#if GNULIB_REALLOCARRAY
@ -38,7 +38,7 @@
with error checking. */
@@ -75,6 +79,8 @@ xirealloc (void *p, idx_t s)
return nonnull (irealloc (p, s));
return check_nonnull (irealloc (p, s));
}
+#if GNULIB_REALLOCARRAY
@ -57,7 +57,24 @@
new size. The new array will contain at least N_INCR_MIN more
--- a/lib/xalloc.h
+++ b/lib/xalloc.h
@@ -129,6 +129,7 @@ char *xstrdup (char const *str)
@@ -81,10 +81,16 @@ void *xrealloc (void *p, size_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2));
void *xirealloc (void *p, idx_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2)) _GL_ATTRIBUTE_RETURNS_NONNULL;
+
+# if GNULIB_REALLOCARRAY
+
void *xreallocarray (void *p, size_t n, size_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2, 3));
void *xireallocarray (void *p, idx_t n, idx_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)) _GL_ATTRIBUTE_RETURNS_NONNULL;
+
+# endif /* GNULIB_REALLOCARRAY */
+
void *x2realloc (void *p, size_t *ps) /* superseded by xpalloc */
_GL_ATTRIBUTE_RETURNS_NONNULL;
void *x2nrealloc (void *p, size_t *pn, size_t s) /* superseded by xpalloc */
@@ -129,6 +135,7 @@ char *xstrdup (char const *str)
# define XCALLOC(n, t) \
((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t))))
@ -65,7 +82,7 @@
/* Allocate an array of N objects, each with S bytes of memory,
dynamically, with error checking. S must be nonzero. */
@@ -156,6 +157,8 @@ char *xcharalloc (size_t n)
@@ -156,6 +163,8 @@ char *xcharalloc (size_t n)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
_GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_RETURNS_NONNULL;
@ -76,26 +93,15 @@
--- a/lib/safe-alloc.h
+++ b/lib/safe-alloc.h
@@ -36,6 +36,8 @@ _GL_INLINE_HEADER_BEGIN
# define SAFE_ALLOC_INLINE _GL_INLINE
@@ -37,7 +37,6 @@ _GL_INLINE_HEADER_BEGIN
extern "C" {
#endif
+#if GNULIB_REALLOCARRAY
+
/* Don't call these directly - use the macros below. */
SAFE_ALLOC_INLINE void *
safe_alloc_realloc_n (void *ptr, size_t count, size_t size)
@@ -51,6 +53,9 @@ safe_alloc_realloc_n (void *ptr, size_t
#endif
return ptr;
}
+
+#endif /* GNULIB_REALLOCARRAY */
+
-
/* Don't call this directly - use the macros below. */
_GL_ATTRIBUTE_NODISCARD SAFE_ALLOC_INLINE int
safe_alloc_check (void *ptr)
{
@@ -84,6 +89,8 @@ safe_alloc_check (void *ptr)
@@ -72,6 +71,8 @@ safe_alloc_check (void *ptr)
#define ALLOC_N(ptr, count) \
safe_alloc_check ((ptr) = calloc (count, sizeof *(ptr)))
@ -104,12 +110,85 @@
/**
* ALLOC_N_UNINITIALIZED:
* @ptr: pointer to allocated memory
@@ -112,6 +119,8 @@ safe_alloc_check (void *ptr)
@@ -100,6 +101,8 @@ safe_alloc_check (void *ptr)
#define REALLOC_N(ptr, count) \
safe_alloc_check ((ptr) = safe_alloc_realloc_n (ptr, count, sizeof *(ptr)))
safe_alloc_check ((ptr) = reallocarray (ptr, count, sizeof *(ptr)))
+#endif /* GNULIB_REALLOCARRAY */
+
/**
* FREE:
* @ptr: pointer holding address to be freed
--- a/lib/dfa.c
+++ b/lib/dfa.c
@@ -1620,6 +1620,8 @@ lex (struct dfa *dfa)
}
}
+#if GNULIB_REALLOCARRAY
+
static void
addtok_mb (struct dfa *dfa, token t, char mbprop)
{
@@ -1674,6 +1676,8 @@ addtok_mb (struct dfa *dfa, token t, cha
}
}
+#endif /* GNULIB_REALLOCARRAY */
+
static void addtok_wc (struct dfa *dfa, wint_t wc);
/* Add the given token to the parse tree, maintaining the depth count and
@@ -2934,6 +2938,8 @@ dfaanalyze (struct dfa *d, bool searchfl
free (tmp.elems);
}
+#if GNULIB_REALLOCARRAY
+
/* Make sure D's state arrays are large enough to hold NEW_STATE. */
static void
realloc_trans_if_necessary (struct dfa *d)
@@ -2969,6 +2975,8 @@ realloc_trans_if_necessary (struct dfa *
}
}
+#endif /* GNULIB_REALLOCARRAY */
+
/*
Calculate the transition table for a new state derived from state s
for a compiled dfa d after input character uc, and return the new
@@ -4010,6 +4018,8 @@ freelist (char **cpp)
free (*cpp++);
}
+#if GNULIB_REALLOCARRAY
+
static char **
enlistnew (char **cpp, char *new)
{
@@ -4046,6 +4056,8 @@ enlist (char **cpp, char const *str, idx
return enlistnew (cpp, ximemdup0 (str, len));
}
+#endif /* GNULIB_REALLOCARRAY */
+
/* Given pointers to two strings, return a pointer to an allocated
list of their distinct common substrings. */
static char **
--- a/lib/readtokens.c
+++ b/lib/readtokens.c
@@ -128,6 +128,8 @@ readtoken (FILE *stream,
return i;
}
+#if GNULIB_REALLOCARRAY
+
/* Build a NULL-terminated array of pointers to tokens
read from STREAM. Return the number of tokens read.
All storage is obtained through calls to xmalloc-like functions.
@@ -190,3 +192,5 @@ readtokens (FILE *stream,
free (lengths);
return n_tokens;
}
+
+#endif /* GNULIB_REALLOCARRAY */

View File

@ -20,8 +20,8 @@
{
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -1447,10 +1447,16 @@ _GL_FUNCDECL_RPL (reallocarray, void *,
(void *ptr, size_t nmemb, size_t size));
@@ -1549,11 +1549,17 @@ _GL_FUNCDECL_RPL (reallocarray, void *,
_GL_ATTRIBUTE_NODISCARD);
_GL_CXXALIAS_RPL (reallocarray, void *,
(void *ptr, size_t nmemb, size_t size));
+# if !GNULIB_defined_rpl_reallocarray
@ -30,7 +30,8 @@
# else
# if ! @HAVE_REALLOCARRAY@
_GL_FUNCDECL_SYS (reallocarray, void *,
(void *ptr, size_t nmemb, size_t size));
(void *ptr, size_t nmemb, size_t size),
_GL_ATTRIBUTE_NODISCARD);
+# if !GNULIB_defined_reallocarray
+# define GNULIB_defined_reallocarray 1
+# endif
@ -49,7 +50,7 @@
reallocarray (void *ptr, size_t nmemb, size_t size)
{
@@ -36,3 +38,5 @@ reallocarray (void *ptr, size_t nmemb, s
/* Rely on the semantics of GNU realloc. */
/* Call realloc, setting errno to ENOMEM on failure. */
return realloc (ptr, nbytes);
}
+

View File

@ -69,7 +69,7 @@
+AC_DEFUN([gl_PREREQ_POSIX_FALLOCATE], [:])
--- a/m4/fcntl_h.m4
+++ b/m4/fcntl_h.m4
@@ -23,7 +23,7 @@ AC_DEFUN_ONCE([gl_FCNTL_H],
@@ -26,7 +26,7 @@ AC_DEFUN_ONCE([gl_FCNTL_H],
dnl corresponding gnulib module is not in use, if it is not common
dnl enough to be declared everywhere.
gl_WARN_ON_USE_PREPARE([[#include <fcntl.h>
@ -78,7 +78,7 @@
])
# gl_FCNTL_MODULE_INDICATOR([modulename])
@@ -50,6 +50,7 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
@@ -53,6 +53,7 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NONBLOCKING])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPEN])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENAT])
@ -86,7 +86,7 @@
dnl Support Microsoft deprecated alias function names by default.
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CREAT], [1])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_OPEN], [1])
@@ -61,10 +62,12 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
@@ -64,10 +65,12 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
AC_DEFUN([gl_FCNTL_H_DEFAULTS],
[
dnl Assume proper GNU behavior unless another module says otherwise.
@ -127,7 +127,7 @@
-e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -238,6 +238,33 @@ _GL_WARN_ON_USE (openat, "openat is not
@@ -241,6 +241,33 @@ _GL_WARN_ON_USE (openat, "openat is not
# endif
#endif
@ -316,7 +316,7 @@
+}
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2552,6 +2552,7 @@ func_all_modules ()
@@ -2555,6 +2555,7 @@ func_all_modules ()
func_module execve
func_module execvp
func_module execvpe

View File

@ -0,0 +1,494 @@
From 5a842672e79a7a5f6be837c483be4f9901a4ecc0 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 30 Apr 2025 03:19:10 +0200
Subject: [PATCH] New module mem-hash-map.
* lib/mem-hash-map.h: New file, from GNU gettext.
* lib/mem-hash-map.c: New file, from GNU gettext.
* modules/mem-hash-map: New file, from GNU gettext.
---
ChangeLog | 7 +
lib/mem-hash-map.c | 352 +++++++++++++++++++++++++++++++++++++++++++
lib/mem-hash-map.h | 90 +++++++++++
modules/mem-hash-map | 25 +++
4 files changed, 474 insertions(+)
create mode 100644 lib/mem-hash-map.c
create mode 100644 lib/mem-hash-map.h
create mode 100644 modules/mem-hash-map
--- /dev/null
+++ b/lib/mem-hash-map.c
@@ -0,0 +1,352 @@
+/* Simple hash table (no removals) where the keys are memory blocks.
+ Copyright (C) 1994-2025 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ This file 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, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "mem-hash-map.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#include "next-prime.h"
+
+/* Since this simple implementation of hash tables allows only insertion, no
+ removal of entries, the right data structure for the memory holding all keys
+ is an obstack. */
+#include "obstack.h"
+
+/* Use checked memory allocation. */
+#include "xalloc.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+
+typedef struct hash_entry
+{
+ size_t used; /* Hash code of the key, or 0 for an unused entry. */
+ const void *key; /* Key. */
+ size_t keylen;
+ void *data; /* Value. */
+ struct hash_entry *next;
+}
+hash_entry;
+
+
+/* Initialize a hash table. INIT_SIZE > 1 is the initial number of available
+ entries.
+ Return 0 always. */
+int
+hash_init (hash_table *htab, size_t init_size)
+{
+ /* We need the size to be a prime. */
+ init_size = next_prime (init_size);
+
+ /* Initialize the data structure. */
+ htab->size = init_size;
+ htab->filled = 0;
+ htab->first = NULL;
+ htab->table = XCALLOC (init_size + 1, hash_entry);
+
+ obstack_init (&htab->mem_pool);
+
+ return 0;
+}
+
+
+/* Delete a hash table's contents.
+ Return 0 always. */
+int
+hash_destroy (hash_table *htab)
+{
+ free (htab->table);
+ obstack_free (&htab->mem_pool, NULL);
+ return 0;
+}
+
+
+/* Compute a hash code for a key consisting of KEYLEN bytes starting at KEY
+ in memory. */
+static size_t
+compute_hashval (const void *key, size_t keylen)
+{
+ size_t cnt;
+ size_t hval;
+
+ /* Compute the hash value for the given string. The algorithm
+ is taken from [Aho,Sethi,Ullman], fixed according to
+ https://haible.de/bruno/hashfunc.html. */
+ cnt = 0;
+ hval = keylen;
+ while (cnt < keylen)
+ {
+ hval = (hval << 9) | (hval >> (sizeof (size_t) * CHAR_BIT - 9));
+ hval += (size_t) *(((const char *) key) + cnt++);
+ }
+ return hval != 0 ? hval : ~((size_t) 0);
+}
+
+
+/* References:
+ [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ [Knuth] The Art of Computer Programming, part3 (6.4) */
+
+/* Look up a given key in the hash table.
+ Return the index of the entry, if present, or otherwise the index a free
+ entry where it could be inserted. */
+static size_t
+lookup (const hash_table *htab,
+ const void *key, size_t keylen,
+ size_t hval)
+{
+ size_t hash;
+ size_t idx;
+ hash_entry *table = htab->table;
+
+ /* First hash function: simply take the modul but prevent zero. */
+ hash = 1 + hval % htab->size;
+
+ idx = hash;
+
+ if (table[idx].used)
+ {
+ if (table[idx].used == hval && table[idx].keylen == keylen
+ && memcmp (table[idx].key, key, keylen) == 0)
+ return idx;
+
+ /* Second hash function as suggested in [Knuth]. */
+ hash = 1 + hval % (htab->size - 2);
+
+ do
+ {
+ if (idx <= hash)
+ idx = htab->size + idx - hash;
+ else
+ idx -= hash;
+
+ /* If entry is found use it. */
+ if (table[idx].used == hval && table[idx].keylen == keylen
+ && memcmp (table[idx].key, key, keylen) == 0)
+ return idx;
+ }
+ while (table[idx].used);
+ }
+ return idx;
+}
+
+
+/* Look up the value of a key in the given table.
+ If found, return 0 and set *RESULT to it. Otherwise return -1. */
+int
+hash_find_entry (const hash_table *htab, const void *key, size_t keylen,
+ void **result)
+{
+ hash_entry *table = htab->table;
+ size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
+
+ if (table[idx].used == 0)
+ return -1;
+
+ *result = table[idx].data;
+ return 0;
+}
+
+
+/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table at index IDX.
+ HVAL is the key's hash code. IDX depends on it. The table entry at index
+ IDX is known to be unused. */
+static void
+insert_entry_2 (hash_table *htab,
+ const void *key, size_t keylen,
+ size_t hval, size_t idx, void *data)
+{
+ hash_entry *table = htab->table;
+
+ table[idx].used = hval;
+ table[idx].key = key;
+ table[idx].keylen = keylen;
+ table[idx].data = data;
+
+ /* List the new value in the list. */
+ if (htab->first == NULL)
+ {
+ table[idx].next = &table[idx];
+ htab->first = &table[idx];
+ }
+ else
+ {
+ table[idx].next = htab->first->next;
+ htab->first->next = &table[idx];
+ htab->first = &table[idx];
+ }
+
+ ++htab->filled;
+}
+
+
+/* Grow the hash table. */
+static void
+resize (hash_table *htab)
+{
+ size_t old_size = htab->size;
+ hash_entry *table = htab->table;
+ size_t idx;
+
+ htab->size = next_prime (htab->size * 2);
+ htab->filled = 0;
+ htab->first = NULL;
+ htab->table = XCALLOC (1 + htab->size, hash_entry);
+
+ for (idx = 1; idx <= old_size; ++idx)
+ if (table[idx].used)
+ insert_entry_2 (htab, table[idx].key, table[idx].keylen,
+ table[idx].used,
+ lookup (htab, table[idx].key, table[idx].keylen,
+ table[idx].used),
+ table[idx].data);
+
+ free (table);
+}
+
+
+/* Try to insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
+ Return non-NULL (more precisely, the address of the KEY inside the table's
+ memory pool) if successful, or NULL if there is already an entry with the
+ given key. */
+const void *
+hash_insert_entry (hash_table *htab,
+ const void *key, size_t keylen,
+ void *data)
+{
+ size_t hval = compute_hashval (key, keylen);
+ hash_entry *table = htab->table;
+ size_t idx = lookup (htab, key, keylen, hval);
+
+ if (table[idx].used)
+ /* We don't want to overwrite the old value. */
+ return NULL;
+ else
+ {
+ /* An empty bucket has been found. */
+ void *keycopy = obstack_copy (&htab->mem_pool, key, keylen);
+ insert_entry_2 (htab, keycopy, keylen, hval, idx, data);
+ if (100 * htab->filled > 75 * htab->size)
+ /* Table is filled more than 75%. Resize the table. */
+ resize (htab);
+ return keycopy;
+ }
+}
+
+
+/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
+ Return 0. */
+int
+hash_set_value (hash_table *htab,
+ const void *key, size_t keylen,
+ void *data)
+{
+ size_t hval = compute_hashval (key, keylen);
+ hash_entry *table = htab->table;
+ size_t idx = lookup (htab, key, keylen, hval);
+
+ if (table[idx].used)
+ {
+ /* Overwrite the old value. */
+ table[idx].data = data;
+ return 0;
+ }
+ else
+ {
+ /* An empty bucket has been found. */
+ void *keycopy = obstack_copy (&htab->mem_pool, key, keylen);
+ insert_entry_2 (htab, keycopy, keylen, hval, idx, data);
+ if (100 * htab->filled > 75 * htab->size)
+ /* Table is filled more than 75%. Resize the table. */
+ resize (htab);
+ return 0;
+ }
+}
+
+
+/* Steps *PTR forward to the next used entry in the given hash table. *PTR
+ should be initially set to NULL. Store information about the next entry
+ in *KEY, *KEYLEN, *DATA.
+ Return 0 normally, -1 when the whole hash table has been traversed. */
+int
+hash_iterate (hash_table *htab, void **ptr, const void **key, size_t *keylen,
+ void **data)
+{
+ hash_entry *curr;
+
+ if (*ptr == NULL)
+ {
+ if (htab->first == NULL)
+ return -1;
+ curr = htab->first;
+ }
+ else
+ {
+ if (*ptr == htab->first)
+ return -1;
+ curr = (hash_entry *) *ptr;
+ }
+ curr = curr->next;
+ *ptr = (void *) curr;
+
+ *key = curr->key;
+ *keylen = curr->keylen;
+ *data = curr->data;
+ return 0;
+}
+
+
+/* Steps *PTR forward to the next used entry in the given hash table. *PTR
+ should be initially set to NULL. Store information about the next entry
+ in *KEY, *KEYLEN, *DATAP. *DATAP is set to point to the storage of the
+ value; modifying **DATAP will modify the value of the entry.
+ Return 0 normally, -1 when the whole hash table has been traversed. */
+int
+hash_iterate_modify (hash_table *htab, void **ptr,
+ const void **key, size_t *keylen,
+ void ***datap)
+{
+ hash_entry *curr;
+
+ if (*ptr == NULL)
+ {
+ if (htab->first == NULL)
+ return -1;
+ curr = htab->first;
+ }
+ else
+ {
+ if (*ptr == htab->first)
+ return -1;
+ curr = (hash_entry *) *ptr;
+ }
+ curr = curr->next;
+ *ptr = (void *) curr;
+
+ *key = curr->key;
+ *keylen = curr->keylen;
+ *datap = &curr->data;
+ return 0;
+}
--- /dev/null
+++ b/lib/mem-hash-map.h
@@ -0,0 +1,90 @@
+/* Simple hash table (no removals) where the keys are memory blocks.
+ Copyright (C) 1995-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ This file 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, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_MEM_HASH_MAP_H
+#define _GL_MEM_HASH_MAP_H
+
+#include <stddef.h>
+
+#include "obstack.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct hash_entry;
+
+typedef struct hash_table
+{
+ size_t size; /* Number of allocated entries. */
+ size_t filled; /* Number of used entries. */
+ struct hash_entry *first; /* Pointer to head of list of entries. */
+ struct hash_entry *table; /* Pointer to array of entries. */
+ struct obstack mem_pool; /* Memory pool holding the keys. */
+}
+hash_table;
+
+/* Initialize a hash table. INIT_SIZE > 1 is the initial number of available
+ entries.
+ Return 0 always. */
+extern int hash_init (hash_table *htab, size_t init_size);
+
+/* Delete a hash table's contents.
+ Return 0 always. */
+extern int hash_destroy (hash_table *htab);
+
+/* Look up the value of a key in the given table.
+ If found, return 0 and set *RESULT to it. Otherwise return -1. */
+extern int hash_find_entry (const hash_table *htab,
+ const void *key, size_t keylen,
+ void **result);
+
+/* Try to insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
+ Return non-NULL (more precisely, the address of the KEY inside the table's
+ memory pool) if successful, or NULL if there is already an entry with the
+ given key. */
+extern const void * hash_insert_entry (hash_table *htab,
+ const void *key, size_t keylen,
+ void *data);
+
+/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
+ Return 0. */
+extern int hash_set_value (hash_table *htab,
+ const void *key, size_t keylen,
+ void *data);
+
+/* Steps *PTR forward to the next used entry in the given hash table. *PTR
+ should be initially set to NULL. Store information about the next entry
+ in *KEY, *KEYLEN, *DATA.
+ Return 0 normally, -1 when the whole hash table has been traversed. */
+extern int hash_iterate (hash_table *htab, void **ptr,
+ const void **key, size_t *keylen,
+ void **data);
+
+/* Steps *PTR forward to the next used entry in the given hash table. *PTR
+ should be initially set to NULL. Store information about the next entry
+ in *KEY, *KEYLEN, *DATAP. *DATAP is set to point to the storage of the
+ value; modifying **DATAP will modify the value of the entry.
+ Return 0 normally, -1 when the whole hash table has been traversed. */
+extern int hash_iterate_modify (hash_table *htab, void **ptr,
+ const void **key, size_t *keylen,
+ void ***datap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not _GL_MEM_HASH_MAP_H */
--- /dev/null
+++ b/modules/mem-hash-map
@@ -0,0 +1,25 @@
+Description:
+Simple hash table (no removals) where the keys are memory blocks.
+
+Files:
+lib/mem-hash-map.h
+lib/mem-hash-map.c
+
+Depends-on:
+next-prime
+obstack
+xalloc
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += mem-hash-map.h mem-hash-map.c
+
+Include:
+"mem-hash-map.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible

View File

@ -0,0 +1,218 @@
From 0b953ba82830f51ce9b939700705d238f9b0c0ba Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 30 Apr 2025 01:52:17 +0200
Subject: [PATCH] New module next-prime.
* lib/next-prime.h: New file, based on lib/hash.c.
* lib/next-prime.c: New file, based on lib/hash.c.
* modules/next-prime: New file.
* lib/hash.c: Include next-prime.h.
(is_prime, next_prime): Remove functions.
* modules/hash (Depends-on): Add next-prime.
---
ChangeLog | 10 +++++++++
lib/hash.c | 39 +-------------------------------
lib/next-prime.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
lib/next-prime.h | 41 +++++++++++++++++++++++++++++++++
modules/hash | 1 +
modules/next-prime | 24 ++++++++++++++++++++
6 files changed, 133 insertions(+), 38 deletions(-)
create mode 100644 lib/next-prime.c
create mode 100644 lib/next-prime.h
create mode 100644 modules/next-prime
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -27,6 +27,7 @@
#include "hash.h"
#include "bitrotate.h"
+#include "next-prime.h"
#include "xalloc-oversized.h"
#include <errno.h>
@@ -390,44 +391,6 @@ hash_string (const char *string, size_t
#endif /* not USE_DIFF_HASH */
-/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd
- number at least equal to 11. */
-
-static bool _GL_ATTRIBUTE_CONST
-is_prime (size_t candidate)
-{
- size_t divisor = 3;
- size_t square = divisor * divisor;
-
- while (square < candidate && (candidate % divisor))
- {
- divisor++;
- square += 4 * divisor;
- divisor++;
- }
-
- return (candidate % divisor ? true : false);
-}
-
-/* Round a given CANDIDATE number up to the nearest prime, and return that
- prime. Primes lower than 10 are merely skipped. */
-
-static size_t _GL_ATTRIBUTE_CONST
-next_prime (size_t candidate)
-{
- /* Skip small primes. */
- if (candidate < 10)
- candidate = 10;
-
- /* Make it definitely odd. */
- candidate |= 1;
-
- while (SIZE_MAX != candidate && !is_prime (candidate))
- candidate += 2;
-
- return candidate;
-}
-
void
hash_reset_tuning (Hash_tuning *tuning)
{
--- /dev/null
+++ b/lib/next-prime.c
@@ -0,0 +1,56 @@
+/* Finding the next prime >= a given small integer.
+ Copyright (C) 1995-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "next-prime.h"
+
+#include <stdint.h> /* for SIZE_MAX */
+
+/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd
+ number at least equal to 11. */
+static bool _GL_ATTRIBUTE_CONST
+is_prime (size_t candidate)
+{
+ size_t divisor = 3;
+ size_t square = divisor * divisor;
+
+ while (square < candidate && (candidate % divisor))
+ {
+ divisor++;
+ square += 4 * divisor;
+ divisor++;
+ }
+
+ return (candidate % divisor ? true : false);
+}
+
+size_t _GL_ATTRIBUTE_CONST
+next_prime (size_t candidate)
+{
+ /* Skip small primes. */
+ if (candidate < 10)
+ candidate = 10;
+
+ /* Make it definitely odd. */
+ candidate |= 1;
+
+ while (SIZE_MAX != candidate && !is_prime (candidate))
+ candidate += 2;
+
+ return candidate;
+}
--- /dev/null
+++ b/lib/next-prime.h
@@ -0,0 +1,41 @@
+/* Finding the next prime >= a given small integer.
+ Copyright (C) 1995-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_NEXT_PRIME_H
+#define _GL_NEXT_PRIME_H
+
+/* This file uses _GL_ATTRIBUTE_CONST. */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Round a given CANDIDATE number up to the nearest prime, and return that
+ prime. Primes lower than 10 are merely skipped. */
+extern size_t _GL_ATTRIBUTE_CONST next_prime (size_t candidate);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_NEXT_PRIME_H */
--- a/modules/hash
+++ b/modules/hash
@@ -10,6 +10,7 @@ bitrotate
calloc-posix
free-posix
malloc-posix
+next-prime
bool
stdint-h
xalloc-oversized
--- /dev/null
+++ b/modules/next-prime
@@ -0,0 +1,24 @@
+Description:
+Finding the next prime >= a given small integer.
+
+Files:
+lib/next-prime.h
+lib/next-prime.c
+
+Depends-on:
+bool
+stdint-h
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += next-prime.h next-prime.c
+
+Include:
+"next-prime.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all

View File

@ -0,0 +1,294 @@
From 64042bb91aea5f854ca8a8938e2b3f7d1935e4f1 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 30 Apr 2025 12:47:37 +0200
Subject: [PATCH] New module hashcode-string1.
* lib/hashcode-string1.h: New file.
* lib/hashcode-string1.c: New file, based on lib/hash.c.
* modules/hashcode-string1: New file.
* lib/hash.h: Include hashcode-string1.h.
(hash_string): Remove declaration.
* lib/hash.c (hash_string): Remove function.
* modules/hash (Depends-on): Add hashcode-string1.
* lib/exclude.c: Include hashcode-string1.h.
* modules/exclude (Depends-on): Add hashcode-string1.
---
ChangeLog | 13 +++++++++
lib/exclude.c | 1 +
lib/hash.c | 59 ++++++--------------------------------
lib/hash.h | 11 +++----
lib/hashcode-string1.c | 62 ++++++++++++++++++++++++++++++++++++++++
lib/hashcode-string1.h | 38 ++++++++++++++++++++++++
modules/exclude | 1 +
modules/hash | 1 +
modules/hashcode-string1 | 24 ++++++++++++++++
9 files changed, 154 insertions(+), 56 deletions(-)
create mode 100644 lib/hashcode-string1.c
create mode 100644 lib/hashcode-string1.h
create mode 100644 modules/hashcode-string1
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -36,6 +36,7 @@
#include "filename.h"
#include <fnmatch.h>
#include "hash.h"
+#include "hashcode-string1.h"
#if GNULIB_MCEL_PREFER
# include "mcel.h"
#else
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -345,57 +345,6 @@ hash_do_for_each (const Hash_table *tabl
return counter;
}
-/* Allocation and clean-up. */
-
-#if USE_DIFF_HASH
-
-/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
- B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
- Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash
- algorithms tend to be domain-specific, so what's good for [diffutils'] io.c
- may not be good for your application." */
-
-size_t
-hash_string (const char *string, size_t n_buckets)
-{
-# define HASH_ONE_CHAR(Value, Byte) \
- ((Byte) + rotl_sz (Value, 7))
-
- size_t value = 0;
- unsigned char ch;
-
- for (; (ch = *string); string++)
- value = HASH_ONE_CHAR (value, ch);
- return value % n_buckets;
-
-# undef HASH_ONE_CHAR
-}
-
-#else /* not USE_DIFF_HASH */
-
-/* This one comes from 'recode', and performs a bit better than the above as
- per a few experiments. It is inspired from a hashing routine found in the
- very old Cyber 'snoop', itself written in typical Greg Mansfield style.
- (By the way, what happened to this excellent man? Is he still alive?) */
-
-size_t
-hash_string (const char *string, size_t n_buckets)
-{
- size_t value = 0;
- unsigned char ch;
-
- for (; (ch = *string); string++)
- value = (value * 31 + ch) % n_buckets;
- return value;
-}
-
-#endif /* not USE_DIFF_HASH */
-
-void
-hash_reset_tuning (Hash_tuning *tuning)
-{
- *tuning = default_tuning;
-}
/* If the user passes a NULL hasher, we hash the raw pointer. */
static size_t
@@ -418,6 +367,14 @@ raw_comparator (const void *a, const voi
}
+/* Allocation and clean-up. */
+
+void
+hash_reset_tuning (Hash_tuning *tuning)
+{
+ *tuning = default_tuning;
+}
+
/* For the given hash TABLE, check the user supplied tuning structure for
reasonable values, and return true if there is no gross error with it.
Otherwise, definitively reset the TUNING field to some acceptable default
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -134,11 +134,6 @@ extern size_t hash_do_for_each (const Ha
* Allocation and clean-up.
*/
-/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
- This is a convenience routine for constructing other hashing functions. */
-extern size_t hash_string (const char *string, size_t n_buckets)
- _GL_ATTRIBUTE_PURE;
-
extern void hash_reset_tuning (Hash_tuning *tuning);
typedef size_t (*Hash_hasher) (const void *entry, size_t table_size);
@@ -266,6 +261,12 @@ extern void *hash_remove (Hash_table *ta
_GL_ATTRIBUTE_DEPRECATED
extern void *hash_delete (Hash_table *table, const void *entry);
+
+# if GNULIB_HASHCODE_STRING1
+/* Include declarations of module 'hashcode-string1'. */
+# include "hashcode-string1.h"
+# endif
+
# ifdef __cplusplus
}
# endif
--- /dev/null
+++ b/lib/hashcode-string1.c
@@ -0,0 +1,62 @@
+/* hashcode-string1.c -- compute a hash value from a NUL-terminated string.
+
+ Copyright (C) 1998-2004, 2006-2007, 2009-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "hashcode-string1.h"
+
+#if USE_DIFF_HASH
+
+# include "bitrotate.h"
+
+/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
+ B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
+ Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash
+ algorithms tend to be domain-specific, so what's good for [diffutils'] io.c
+ may not be good for your application." */
+
+size_t
+hash_string (const char *string, size_t tablesize)
+{
+ size_t value = 0;
+ unsigned char ch;
+
+ for (; (ch = *string); string++)
+ value = ch + rotl_sz (value, 7);
+ return value % tablesize;
+}
+
+#else /* not USE_DIFF_HASH */
+
+/* This one comes from 'recode', and performs a bit better than the above as
+ per a few experiments. It is inspired from a hashing routine found in the
+ very old Cyber 'snoop', itself written in typical Greg Mansfield style.
+ (By the way, what happened to this excellent man? Is he still alive?) */
+
+size_t
+hash_string (const char *string, size_t tablesize)
+{
+ size_t value = 0;
+ unsigned char ch;
+
+ for (; (ch = *string); string++)
+ value = (value * 31 + ch) % tablesize;
+ return value;
+}
+
+#endif /* not USE_DIFF_HASH */
--- /dev/null
+++ b/lib/hashcode-string1.h
@@ -0,0 +1,38 @@
+/* hashcode-string1.h -- declaration for a simple hash function
+ Copyright (C) 1998-2004, 2006-2007, 2009-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* This file uses _GL_ATTRIBUTE_PURE. */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Compute a hash code for a NUL-terminated string S,
+ and return the hash code modulo TABLESIZE.
+ The result is platform dependent: it depends on the size of the 'size_t'
+ type. */
+extern size_t hash_string (char const *s, size_t tablesize) _GL_ATTRIBUTE_PURE;
+
+
+#ifdef __cplusplus
+}
+#endif
--- a/modules/exclude
+++ b/modules/exclude
@@ -12,6 +12,7 @@ filename
fnmatch
fopen-gnu
hash
+hashcode-string1
mbscasecmp
mbuiter [test "$GNULIB_MCEL_PREFER" != yes]
nullptr
--- a/modules/hash
+++ b/modules/hash
@@ -14,6 +14,7 @@ next-prime
bool
stdint-h
xalloc-oversized
+hashcode-string1
configure.ac:
--- /dev/null
+++ b/modules/hashcode-string1
@@ -0,0 +1,24 @@
+Description:
+Compute a hash value for a NUL-terminated string.
+
+Files:
+lib/hashcode-string1.h
+lib/hashcode-string1.c
+
+Depends-on:
+bitrotate
+
+configure.ac:
+gl_MODULE_INDICATOR([hashcode-string1])
+
+Makefile.am:
+lib_SOURCES += hashcode-string1.h hashcode-string1.c
+
+Include:
+"hashcode-string1.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Jim Meyering

View File

@ -0,0 +1,215 @@
From 52738dcd0f522b16653cc8b21adfcb758702f2ab Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 30 Apr 2025 01:20:17 +0200
Subject: [PATCH] New module hashkey-string.
* lib/hashkey-string.h: New file.
* lib/hashkey-string.c: New file, based on lib/clean-temp-simple.c.
* modules/hashkey-string: New file.
* lib/clean-temp-simple.c: Include hashkey-string.h. Don't include
<limits.h>.
(clean_temp_string_equals, clean_temp_string_hash): Remove functions.
(SIZE_BITS): Remove macro.
(register_temporary_file): Use hashkey_string_equals and
hashkey_string_hash.
* modules/clean-temp-simple (Depends-on): Add hashkey-string.
---
ChangeLog | 14 ++++++++++++
lib/clean-temp-simple.c | 33 +++------------------------
lib/hashkey-string.c | 48 +++++++++++++++++++++++++++++++++++++++
lib/hashkey-string.h | 35 ++++++++++++++++++++++++++++
modules/clean-temp-simple | 1 +
modules/hashkey-string | 23 +++++++++++++++++++
6 files changed, 124 insertions(+), 30 deletions(-)
create mode 100644 lib/hashkey-string.c
create mode 100644 lib/hashkey-string.h
create mode 100644 modules/hashkey-string
--- a/lib/clean-temp-simple.c
+++ b/lib/clean-temp-simple.c
@@ -22,7 +22,6 @@
#include "clean-temp-private.h"
#include <errno.h>
-#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -36,6 +35,7 @@
#include "thread-optim.h"
#include "gl_list.h"
#include "gl_linkedhash_list.h"
+#include "hashkey-string.h"
#include "gettext.h"
#define _(msgid) dgettext ("gnulib", msgid)
@@ -106,33 +106,6 @@ gl_list_t /* <closeable_fd *> */ volatil
asynchronous signal.
*/
-/* String equality and hash code functions used by the lists. */
-
-bool
-clean_temp_string_equals (const void *x1, const void *x2)
-{
- const char *s1 = (const char *) x1;
- const char *s2 = (const char *) x2;
- return strcmp (s1, s2) == 0;
-}
-
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
-/* A hash function for NUL-terminated char* strings using
- the method described by Bruno Haible.
- See https://www.haible.de/bruno/hashfunc.html. */
-size_t
-clean_temp_string_hash (const void *x)
-{
- const char *s = (const char *) x;
- size_t h = 0;
-
- for (; *s; s++)
- h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
-
- return h;
-}
-
/* The set of fatal signal handlers.
Cached here because we are not allowed to call get_fatal_signal_set ()
@@ -326,8 +299,8 @@ register_temporary_file (const char *abs
}
file_cleanup_list =
gl_list_nx_create_empty (GL_LINKEDHASH_LIST,
- clean_temp_string_equals,
- clean_temp_string_hash,
+ hashkey_string_equals,
+ hashkey_string_hash,
NULL, false);
if (file_cleanup_list == NULL)
{
--- /dev/null
+++ b/lib/hashkey-string.c
@@ -0,0 +1,48 @@
+/* Support for using a string as a hash key.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include "hashkey-string.h"
+
+#include <limits.h>
+#include <string.h>
+
+bool
+hashkey_string_equals (const void *x1, const void *x2)
+{
+ const char *s1 = (const char *) x1;
+ const char *s2 = (const char *) x2;
+ return strcmp (s1, s2) == 0;
+}
+
+#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
+
+/* A hash function for NUL-terminated 'const char *' strings using
+ the method described by Bruno Haible.
+ See https://www.haible.de/bruno/hashfunc.html. */
+size_t
+hashkey_string_hash (const void *x)
+{
+ const char *s = (const char *) x;
+ size_t h = 0;
+
+ for (; *s; s++)
+ h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+
+ return h;
+}
--- /dev/null
+++ b/lib/hashkey-string.h
@@ -0,0 +1,35 @@
+/* Support for using a string as a hash key.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_HASHKEY_STRING_H
+#define _GL_HASHKEY_STRING_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* String equality and hash code functions that operate on plain C strings
+ ('const char *'). */
+extern bool hashkey_string_equals (const void *x1, const void *x2);
+extern size_t hashkey_string_hash (const void *x);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_HASHKEY_STRING_H */
--- a/modules/clean-temp-simple
+++ b/modules/clean-temp-simple
@@ -19,6 +19,7 @@ error
fatal-signal
rmdir
linkedhash-list
+hashkey-string
gettext-h
gnulib-i18n
--- /dev/null
+++ b/modules/hashkey-string
@@ -0,0 +1,23 @@
+Description:
+Support for using a string as a hash key in the hash-set and hash-map modules.
+
+Files:
+lib/hashkey-string.h
+lib/hashkey-string.c
+
+Depends-on:
+bool
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += hashkey-string.h hashkey-string.c
+
+Include:
+"hashkey-string.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all

View File

@ -0,0 +1,176 @@
From e518788ad085e02b046e42889039a1f671e4619a Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 22 Jan 2025 21:21:59 +0100
Subject: New module 'package-version'.
* m4/init-package-version.m4: New file, from GNU libunistring.
* modules/package-version: New file.
* modules/git-version-gen (Depends-on): Add it.
---
ChangeLog | 7 +++
m4/init-package-version.m4 | 124 +++++++++++++++++++++++++++++++++++++++++++++
modules/git-version-gen | 1 +
modules/package-version | 19 +++++++
4 files changed, 151 insertions(+)
create mode 100644 m4/init-package-version.m4
create mode 100644 modules/package-version
--- /dev/null
+++ b/m4/init-package-version.m4
@@ -0,0 +1,124 @@
+# init-package-version.m4
+# serial 3
+dnl Copyright (C) 1992-2025 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+# Make it possible to pass version numbers extracted from a file in
+# $(srcdir) to autoconf.
+#
+# Autoconf insists on passing the package name and version number to
+# every generated .h file and every Makefile. This was a reasonable
+# design at times when a version number was changed only once a month.
+# Nowadays, people often assign a new version number once a week, or
+# even change it each time a 'git' commit is made. Regenerating all
+# the files that depend on configure.ac (aclocal.m4, configure,
+# config.status, config.h, all Makefiles) may take 15 minutes. These
+# delays can severely hamper development.
+#
+# An alternative is to store the version number in a file in $(srcdir)
+# that is separate from configure.ac. It can be a data file, a shell
+# script, a .m4 file, or other. The essential point is that the maintainer
+# is responsible for creating Makefile dependencies to this version file
+# for every file that needs to be rebuilt when the version changes. This
+# typically includes
+# - distributable documentation files that carry the version number,
+# but does not include
+# - aclocal.m4, configure, config.status, config.h, all Makefiles,
+# - executables.
+#
+# autoconf and automake make it hard to follow this approach:
+#
+# - If AC_INIT is used with arguments, there is a chicken-and-egg problem:
+# The arguments need to be read from a file in $(srcdir). The location
+# of $(srcdir) is only determined by AC_CONFIG_SRCDIR. AC_CONFIG_SRCDIR
+# can only appear after AC_INIT (otherwise aclocal gives an error:
+# "error: m4_defn: undefined macro: _m4_divert_diversion").
+# Furthermore, the arguments passed to AC_INIT must be literals; for
+# example, the assignment to PACKAGE_VERSION looks like this:
+# [PACKAGE_VERSION=']AC_PACKAGE_VERSION[']
+#
+# - If AC_INIT is used without arguments:
+# Automake provides its own variables, PACKAGE and VERSION, and uses them
+# instead of PACKAGE_NAME and PACKAGE_VERSION that come from Autoconf.
+# - If AM_INIT_AUTOMAKE is used with two arguments, automake options
+# like 'silent-rules' cannot be specified.
+# - If AM_INIT_AUTOMAKE is used in its one-argument form or without
+# arguments at all, it triggers an error
+# "error: AC_INIT should be called with package and version arguments".
+# - If AM_INIT_AUTOMAKE is used in its one-argument form or without
+# arguments at all, and _AC_INIT_PACKAGE is used before it, with
+# the package and version number from the file as arguments, we get
+# a warning: "warning: AC_INIT: not a literal: $VERSION_NUMBER".
+# The arguments passed to _AC_INIT_PACKAGE must be literals.
+#
+# With the macro defined in this file, the approach can be coded like this:
+#
+# AC_INIT
+# AC_CONFIG_SRCDIR(WITNESS)
+# . $srcdir/../version.sh
+# gl_INIT_PACKAGE(PACKAGE, $VERSION_NUMBER)
+# AM_INIT_AUTOMAKE([OPTIONS])
+#
+# and after changing version.sh, the developer can directly configure and build:
+#
+# make distclean
+# ./configure
+# make
+#
+# Some other packages use another approach:
+#
+# AC_INIT(PACKAGE,
+# m4_normalize(m4_esyscmd([. ./version.sh; echo $VERSION_NUMBER])))
+# AC_CONFIG_SRCDIR(WITNESS)
+# AM_INIT_AUTOMAKE([OPTIONS])
+#
+# but here, after changing version.sh, the developer must first regenerate the
+# configure file:
+#
+# make distclean
+# ./autogen.sh --skip-gnulib
+# ./configure
+# make
+#
+
+# gl_INIT_PACKAGE(PACKAGE-NAME, VERSION)
+# --------------------------------------
+# followed by an AM_INIT_AUTOMAKE invocation,
+# is like calling AM_INIT_AUTOMAKE(PACKAGE-NAME, VERSION)
+# except that it can use computed non-literal arguments.
+AC_DEFUN([gl_INIT_PACKAGE],
+[
+ AC_BEFORE([$0], [AM_INIT_AUTOMAKE])
+ dnl Redefine AM_INIT_AUTOMAKE.
+ m4_define([gl_AM_INIT_AUTOMAKE],
+ m4_bpatsubst(m4_dquote(
+ m4_bpatsubst(m4_dquote(
+ m4_bpatsubst(m4_dquote(
+ m4_defn([AM_INIT_AUTOMAKE])),
+ [AC_PACKAGE_NAME], [gl_INIT_DUMMY])),
+ [AC_PACKAGE_TARNAME], [gl_INIT_EMPTY])),
+ [AC_PACKAGE_VERSION], [gl_INIT_DUMMY])
+ [AC_SUBST([PACKAGE], [$1])
+ AC_SUBST([VERSION], [$2])
+ ])
+ m4_define([AM_INIT_AUTOMAKE],
+ m4_defn([gl_RPL_INIT_AUTOMAKE]))
+])
+m4_define([gl_INIT_EMPTY], [])
+dnl Automake 1.16.4 no longer accepts an empty value for gl_INIT_DUMMY.
+dnl But a macro that later expands to empty works.
+m4_define([gl_INIT_DUMMY], [gl_INIT_DUMMY2])
+m4_define([gl_INIT_DUMMY2], [])
+AC_DEFUN([gl_RPL_INIT_AUTOMAKE], [
+ m4_ifval([$2],
+ [m4_fatal([After gl_INIT_PACKAGE, the two-argument form of AM_INIT_AUTOMAKE cannot be used.])])
+ gl_AM_INIT_AUTOMAKE([$1 no-define])
+ m4_if(m4_index([ $1 ], [ no-define ]), [-1],
+ [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])
+ ])
+])
--- a/modules/git-version-gen
+++ b/modules/git-version-gen
@@ -5,6 +5,7 @@ Files:
build-aux/git-version-gen
Depends-on:
+package-version
configure.ac:
--- /dev/null
+++ b/modules/package-version
@@ -0,0 +1,19 @@
+Description:
+Support for a computed version string.
+
+Files:
+m4/init-package-version.m4
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+
+Include:
+
+License:
+GPLed build tool
+
+Maintainer:
+Bruno Haible

View File

@ -0,0 +1,66 @@
From bb0f82be83d43db9cd77049be32ffd0b92ab5bb7 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 24 Jan 2025 22:03:29 +0100
Subject: package-version: Simplify its use.
Reported by Basil L. Contovounesios <basil@contovou.net> in
<https://lists.gnu.org/archive/html/bug-gnulib/2025-01/msg00195.html>.
* doc/package-version.texi (Propagating the package version): Recommend
to pass the usual arguments to AC_INIT.
* m4/init-package-version.m4: Likewise.
(gl_INIT_PACKAGE): Define PACKAGE_VERSION and PACKAGE_STRING as needed.
(gl_RPL_INIT_AUTOMAKE): Improve quoting.
---
ChangeLog | 11 +++++++++++
doc/package-version.texi | 2 +-
m4/init-package-version.m4 | 20 ++++++++++++++------
3 files changed, 26 insertions(+), 7 deletions(-)
--- a/m4/init-package-version.m4
+++ b/m4/init-package-version.m4
@@ -1,5 +1,5 @@
# init-package-version.m4
-# serial 3
+# serial 4
dnl Copyright (C) 1992-2025 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
@@ -57,7 +57,7 @@ dnl the same distribution terms as the r
#
# With the macro defined in this file, the approach can be coded like this:
#
-# AC_INIT
+# AC_INIT(PACKAGE, [dummy], [MORE OPTIONS])
# AC_CONFIG_SRCDIR(WITNESS)
# . $srcdir/../version.sh
# gl_INIT_PACKAGE(PACKAGE, $VERSION_NUMBER)
@@ -102,8 +102,16 @@ AC_DEFUN([gl_INIT_PACKAGE],
[AC_PACKAGE_NAME], [gl_INIT_DUMMY])),
[AC_PACKAGE_TARNAME], [gl_INIT_EMPTY])),
[AC_PACKAGE_VERSION], [gl_INIT_DUMMY])
- [AC_SUBST([PACKAGE], [$1])
- AC_SUBST([VERSION], [$2])
+ [dnl Set variables documented in Automake.
+ AC_SUBST([PACKAGE], [$1])
+ AC_SUBST([VERSION], ["$2"])
+ dnl Set variables documented in Autoconf.
+ AC_SUBST([PACKAGE_VERSION], ["$2"])
+ AC_SUBST([PACKAGE_STRING], ["$1 $2"])
+ AC_DEFINE_UNQUOTED([PACKAGE_VERSION], ["$2"],
+ [Define to the version of this package.])
+ AC_DEFINE_UNQUOTED([PACKAGE_STRING], ["$1 $2"],
+ [Define to the full name and version of this package.])
])
m4_define([AM_INIT_AUTOMAKE],
m4_defn([gl_RPL_INIT_AUTOMAKE]))
@@ -118,7 +126,7 @@ AC_DEFUN([gl_RPL_INIT_AUTOMAKE], [
[m4_fatal([After gl_INIT_PACKAGE, the two-argument form of AM_INIT_AUTOMAKE cannot be used.])])
gl_AM_INIT_AUTOMAKE([$1 no-define])
m4_if(m4_index([ $1 ], [ no-define ]), [-1],
- [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
- AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])
+ [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])
])
])

View File

@ -0,0 +1,89 @@
From 48648b4b9b3fd79a5c68913deb28678bd9d8eb34 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 25 Jan 2025 04:07:32 +0100
Subject: package-version: Simplify further.
* doc/package-version.texi (Propagating the package version): Recommend
use of gl_INIT_PACKAGE_VERSION instead of gl_INIT_PACKAGE.
* build-aux/git-version-gen: Likewise.
* m4/init-package-version.m4: Likewise.
(gl_INIT_PACKAGE_VERSION): Renamed from gl_INIT_PACKAGE. Take only one
argument. Don't fiddle with AC_PACKAGE_NAME, AC_PACKAGE_TARNAME,
PACKAGE.
(gl_RPL_INIT_AUTOMAKE): Update.
---
ChangeLog | 10 ++++++++++
build-aux/git-version-gen | 4 ++--
doc/package-version.texi | 4 ++--
m4/init-package-version.m4 | 30 ++++++++++++------------------
4 files changed, 26 insertions(+), 22 deletions(-)
--- a/m4/init-package-version.m4
+++ b/m4/init-package-version.m4
@@ -1,5 +1,5 @@
# init-package-version.m4
-# serial 4
+# serial 5
dnl Copyright (C) 1992-2025 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
@@ -60,7 +60,7 @@ dnl the same distribution terms as the r
# AC_INIT(PACKAGE, [dummy], [MORE OPTIONS])
# AC_CONFIG_SRCDIR(WITNESS)
# . $srcdir/../version.sh
-# gl_INIT_PACKAGE(PACKAGE, $VERSION_NUMBER)
+# gl_INIT_PACKAGE_VERSION($VERSION_NUMBER)
# AM_INIT_AUTOMAKE([OPTIONS])
#
# and after changing version.sh, the developer can directly configure and build:
@@ -85,32 +85,26 @@ dnl the same distribution terms as the r
# make
#
-# gl_INIT_PACKAGE(PACKAGE-NAME, VERSION)
-# --------------------------------------
+# gl_INIT_PACKAGE_VERSION(VERSION)
+# --------------------------------
# followed by an AM_INIT_AUTOMAKE invocation,
# is like calling AM_INIT_AUTOMAKE(PACKAGE-NAME, VERSION)
# except that it can use computed non-literal arguments.
-AC_DEFUN([gl_INIT_PACKAGE],
+AC_DEFUN([gl_INIT_PACKAGE_VERSION],
[
AC_BEFORE([$0], [AM_INIT_AUTOMAKE])
dnl Redefine AM_INIT_AUTOMAKE.
m4_define([gl_AM_INIT_AUTOMAKE],
- m4_bpatsubst(m4_dquote(
- m4_bpatsubst(m4_dquote(
- m4_bpatsubst(m4_dquote(
- m4_defn([AM_INIT_AUTOMAKE])),
- [AC_PACKAGE_NAME], [gl_INIT_DUMMY])),
- [AC_PACKAGE_TARNAME], [gl_INIT_EMPTY])),
+ m4_bpatsubst(m4_dquote(m4_defn([AM_INIT_AUTOMAKE])),
[AC_PACKAGE_VERSION], [gl_INIT_DUMMY])
[dnl Set variables documented in Automake.
- AC_SUBST([PACKAGE], [$1])
- AC_SUBST([VERSION], ["$2"])
+ AC_SUBST([VERSION], ["$1"])
dnl Set variables documented in Autoconf.
- AC_SUBST([PACKAGE_VERSION], ["$2"])
- AC_SUBST([PACKAGE_STRING], ["$1 $2"])
- AC_DEFINE_UNQUOTED([PACKAGE_VERSION], ["$2"],
+ AC_SUBST([PACKAGE_VERSION], ["$1"])
+ AC_SUBST([PACKAGE_STRING], ["AC_PACKAGE_NAME $1"])
+ AC_DEFINE_UNQUOTED([PACKAGE_VERSION], ["$1"],
[Define to the version of this package.])
- AC_DEFINE_UNQUOTED([PACKAGE_STRING], ["$1 $2"],
+ AC_DEFINE_UNQUOTED([PACKAGE_STRING], ["AC_PACKAGE_NAME $1"],
[Define to the full name and version of this package.])
])
m4_define([AM_INIT_AUTOMAKE],
@@ -123,7 +117,7 @@ m4_define([gl_INIT_DUMMY], [gl_INIT_DUMM
m4_define([gl_INIT_DUMMY2], [])
AC_DEFUN([gl_RPL_INIT_AUTOMAKE], [
m4_ifval([$2],
- [m4_fatal([After gl_INIT_PACKAGE, the two-argument form of AM_INIT_AUTOMAKE cannot be used.])])
+ [m4_fatal([After gl_INIT_PACKAGE_VERSION, the two-argument form of AM_INIT_AUTOMAKE cannot be used.])])
gl_AM_INIT_AUTOMAKE([$1 no-define])
m4_if(m4_index([ $1 ], [ no-define ]), [-1],
[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])

View File

@ -0,0 +1,32 @@
From 2e46209809f751087ca27523283bd5c3e9071d31 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sun, 26 Jan 2025 13:26:35 +0100
Subject: package-version: Avoid compiler warnings in config.log.
* m4/init-package-version.m4 (gl_INIT_PACKAGE_VERSION): Undefine
PACKAGE_VERSION and PACKAGE_STRING before redefining them.
---
ChangeLog | 6 ++++++
m4/init-package-version.m4 | 4 +++-
2 files changed, 9 insertions(+), 1 deletion(-)
--- a/m4/init-package-version.m4
+++ b/m4/init-package-version.m4
@@ -1,5 +1,5 @@
# init-package-version.m4
-# serial 5
+# serial 6
dnl Copyright (C) 1992-2025 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
@@ -102,8 +102,10 @@ AC_DEFUN([gl_INIT_PACKAGE_VERSION],
dnl Set variables documented in Autoconf.
AC_SUBST([PACKAGE_VERSION], ["$1"])
AC_SUBST([PACKAGE_STRING], ["AC_PACKAGE_NAME $1"])
+ _AC_DEFINE([#undef PACKAGE_VERSION])
AC_DEFINE_UNQUOTED([PACKAGE_VERSION], ["$1"],
[Define to the version of this package.])
+ _AC_DEFINE([#undef PACKAGE_STRING])
AC_DEFINE_UNQUOTED([PACKAGE_STRING], ["AC_PACKAGE_NAME $1"],
[Define to the full name and version of this package.])
])

View File

@ -0,0 +1,75 @@
From 85599643e2fbf70f7f0bd58831993132ef335705 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 22 Jan 2025 21:25:27 +0100
Subject: New module 'version-stamp'.
* m4/version-stamp.m4: New file.
* modules/version-stamp: New file.
---
ChangeLog | 6 ++++++
m4/version-stamp.m4 | 35 +++++++++++++++++++++++++++++++++++
modules/version-stamp | 19 +++++++++++++++++++
3 files changed, 60 insertions(+)
create mode 100644 m4/version-stamp.m4
create mode 100644 modules/version-stamp
--- /dev/null
+++ b/m4/version-stamp.m4
@@ -0,0 +1,35 @@
+# version-stamp.m4
+# serial 1
+dnl Copyright (C) 2025 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+# Manages a stamp file, that keeps track when $(VERSION) was last changed.
+#
+# gl_CONFIG_VERSION_STAMP
+# needs to be invoked near the end of the package's top-level configure.ac,
+# before AC_OUTPUT.
+# It makes sure that during the build,
+# - $(top_srcdir)/.version exists, and
+# - when $(VERSION) is changed, $(top_srcdir)/.version gets modified.
+#
+# $(top_srcdir)/.version is a stamp file. Its contents wouldn't matter,
+# except that for detecting the change, we store the value of $(VERSION)
+# in it (but we could just as well store it in a different file).
+AC_DEFUN([gl_CONFIG_VERSION_STAMP],
+[
+ AC_CONFIG_COMMANDS([version-timestamp],
+ [if test -f "$ac_top_srcdir/.version" \
+ && test `cat "$ac_top_srcdir/.version"` = "$gl_version"; then
+ # The value of $(VERSION) is the same as last time.
+ :
+ else
+ # The value of $(VERSION) has changed. Update the stamp.
+ echo "$gl_version" > "$ac_top_srcdir/.version"
+ fi
+ ],
+ [gl_version="$VERSION"])
+])
--- /dev/null
+++ b/modules/version-stamp
@@ -0,0 +1,19 @@
+Description:
+Optimized rebuilding of artifacts that depend on $(VERSION).
+
+Files:
+m4/version-stamp.m4
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+
+Include:
+
+License:
+GPLed build tool
+
+Maintainer:
+Bruno Haible

View File

@ -0,0 +1,366 @@
From 701d20aaf579bb71f35209dd63a272c3d9d21096 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Mon, 24 Feb 2025 19:03:17 +0100
Subject: [PATCH] vc-mtime: New module.
* lib/vc-mtime.h: New file.
* lib/vc-mtime.c: New file.
* modules/vc-mtime: New file.
---
ChangeLog | 7 ++
lib/vc-mtime.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++
lib/vc-mtime.h | 97 ++++++++++++++++++++++
modules/vc-mtime | 34 ++++++++
4 files changed, 346 insertions(+)
create mode 100644 lib/vc-mtime.c
create mode 100644 lib/vc-mtime.h
create mode 100644 modules/vc-mtime
--- /dev/null
+++ b/lib/vc-mtime.c
@@ -0,0 +1,208 @@
+/* Return the version-control based modification time of a file.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
+
+#include <config.h>
+
+/* Specification. */
+#include "vc-mtime.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <error.h>
+#include "spawn-pipe.h"
+#include "wait-process.h"
+#include "execute.h"
+#include "safe-read.h"
+#include "xstrtol.h"
+#include "stat-time.h"
+#include "gettext.h"
+
+#define _(msgid) dgettext ("gnulib", msgid)
+
+
+/* Determines whether the specified file is under version control. */
+static bool
+git_vc_controlled (const char *filename)
+{
+ /* Run "git ls-files FILENAME" and return true if the exit code is 0
+ and the output is non-empty. */
+ const char *argv[4];
+ pid_t child;
+ int fd[1];
+
+ argv[0] = "git";
+ argv[1] = "ls-files";
+ argv[2] = filename;
+ argv[3] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ return false;
+
+ /* Read the subprocess output, and test whether it is non-empty. */
+ size_t count = 0;
+ char c;
+
+ while (safe_read (fd[0], &c, 1) > 0)
+ count++;
+
+ close (fd[0]);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ int exitstatus =
+ wait_subprocess (child, "git", false, true, true, false, NULL);
+ return (exitstatus == 0 && count > 0);
+}
+
+/* Determines whether the specified file is unmodified, compared to the
+ last version in version control. */
+static bool
+git_unmodified (const char *filename)
+{
+ /* Run "git diff --quiet -- HEAD FILENAME"
+ (or "git diff --quiet HEAD FILENAME")
+ and return true if the exit code is 0.
+ The '--' option is for the case that the specified file was removed. */
+ const char *argv[7];
+ int exitstatus;
+
+ argv[0] = "git";
+ argv[1] = "diff";
+ argv[2] = "--quiet";
+ argv[3] = "--";
+ argv[4] = "HEAD";
+ argv[5] = filename;
+ argv[6] = NULL;
+ exitstatus = execute ("git", "git", argv, NULL, NULL,
+ false, false, true, true,
+ true, false, NULL);
+ return (exitstatus == 0);
+}
+
+/* Stores in *MTIME the time of last modification in version control of the
+ specified file, and returns 0.
+ Upon failure, it returns -1. */
+static int
+git_mtime (struct timespec *mtime, const char *filename)
+{
+ /* Run "git log -1 --format=%ct -- FILENAME". It prints the time of last
+ modification, as the number of seconds since the Epoch.
+ The '--' option is for the case that the specified file was removed. */
+ const char *argv[7];
+ pid_t child;
+ int fd[1];
+
+ argv[0] = "git";
+ argv[1] = "log";
+ argv[2] = "-1";
+ argv[3] = "--format=%ct";
+ argv[4] = "--";
+ argv[5] = filename;
+ argv[6] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ return -1;
+
+ /* Retrieve its result. */
+ FILE *fp;
+ char *line;
+ size_t linesize;
+ size_t linelen;
+
+ fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ line = NULL; linesize = 0;
+ linelen = getline (&line, &linesize, fp);
+ if (linelen == (size_t)(-1))
+ {
+ error (0, 0, _("%s subprocess I/O error"), "git");
+ fclose (fp);
+ wait_subprocess (child, "git", true, false, true, false, NULL);
+ }
+ else
+ {
+ int exitstatus;
+
+ if (linelen > 0 && line[linelen - 1] == '\n')
+ line[linelen - 1] = '\0';
+
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ exitstatus =
+ wait_subprocess (child, "git", true, false, true, false, NULL);
+ if (exitstatus == 0)
+ {
+ char *endptr;
+ unsigned long git_log_time;
+ if (xstrtoul (line, &endptr, 10, &git_log_time, NULL) == LONGINT_OK
+ && endptr == line + strlen (line))
+ {
+ mtime->tv_sec = git_log_time;
+ mtime->tv_nsec = 0;
+ free (line);
+ return 0;
+ }
+ }
+ }
+ free (line);
+ return -1;
+}
+
+int
+vc_mtime (struct timespec *mtime, const char *filename)
+{
+ static bool git_tested;
+ static bool git_present;
+
+ if (!git_tested)
+ {
+ /* Test for presence of git:
+ "git --version >/dev/null 2>/dev/null" */
+ const char *argv[3];
+ int exitstatus;
+
+ argv[0] = "git";
+ argv[1] = "--version";
+ argv[2] = NULL;
+ exitstatus = execute ("git", "git", argv, NULL, NULL,
+ false, false, true, true,
+ true, false, NULL);
+ git_present = (exitstatus == 0);
+ git_tested = true;
+ }
+
+ if (git_present
+ && git_vc_controlled (filename)
+ && git_unmodified (filename))
+ {
+ if (git_mtime (mtime, filename) == 0)
+ return 0;
+ }
+ struct stat statbuf;
+ if (stat (filename, &statbuf) == 0)
+ {
+ *mtime = get_stat_mtime (&statbuf);
+ return 0;
+ }
+ return -1;
+}
--- /dev/null
+++ b/lib/vc-mtime.h
@@ -0,0 +1,97 @@
+/* Return the version-control based modification time of a file.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
+
+#ifndef _VC_MTIME_H
+#define _VC_MTIME_H
+
+/* Get struct timespec. */
+#include <time.h>
+
+/* The "version-controlled modification time" vc_mtime(F) of a file F
+ is defined as:
+ - If F is under version control and not modified locally:
+ the time of the last change of F in the version control system.
+ - Otherwise: The modification time of F on disk.
+
+ For now, the only VCS supported by this module is git. (hg and svn are
+ hardly in use any more.)
+
+ This has the properties that:
+ - Different users who have checked out the same git repo on different
+ machines, at different times, and not done local modifications,
+ get the same vc_mtime(F).
+ - If a user has modified F locally, the modification time of that file
+ counts.
+ - If that user then reverts the modification, they then again get the
+ same vc_mtime(F) as everyone else.
+ - Different users who have unpacked the same tarball (without .git
+ directory) on different machines, at different times, also get the same
+ vc_mtime(F) [but possibly a different one than when the .git directory
+ was present]. (Assuming a POSIX compliant file system.)
+ - When a user commits local modifications into git, this only increases
+ (not decreases) the vc_mtime(F).
+
+ The purpose of the version-controlled modification time is to produce a
+ reproducible timestamp(Z) of a file Z that depends on files X1, ..., Xn,
+ in such a way that
+ - timestamp(Z) is reproducible, that is, different users on different
+ machines get the same value.
+ - timestamp(Z) is related to reality. It's not just a dummy, like what
+ is suggested in <https://reproducible-builds.org/docs/timestamps/>.
+ - One can arrange for timestamp(Z) to respect the modification time
+ relations of a build system.
+
+ There are two uses of such a timestamp:
+ - It can be set as the modification time of file Z in a file system, or
+ - It can be embedded in Z, with the purpose of telling a user how old
+ the file Z is. For example, in PDF files or in generated documentation,
+ such a time is embedded in a special place.
+
+ The simplest example is a file Z that depends on files X1, ..., Xn.
+ Generally one will define
+ timestamp(Z) = max (vc_mtime(X1), ..., vc_mtime(Xn))
+ for an embedded timestamp, or
+ timestamp(Z) = max (vc_mtime(X1), ..., vc_mtime(Xn)) + 1 second
+ for a time stamp in a file system. The added second
+ 1. accounts for fractional seconds in mtime(X1), ..., mtime(Xn),
+ 2. allows for 'make' implementation that attempt to rebuild Z
+ if mtime(Z) == mtime(Xi).
+
+ A more complicated example is when there are intermediate built files, not
+ under version control. For example, if the build process produces
+ X1, X2 -> Y1
+ X3, X4 -> Y2
+ Y1, Y2, X5 -> Z
+ where Y1 and Y2 are intermediate built files, you should ignore the
+ mtime(Y1), mtime(Y2), and consider only the vc_mtime(X1), ..., vc_mtime(X5).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Determines the version-controlled modification time of FILENAME, stores it
+ in *MTIME, and returns 0.
+ Upon failure, it returns -1. */
+extern int vc_mtime (struct timespec *mtime, const char *filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VC_MTIME_H */
--- /dev/null
+++ b/modules/vc-mtime
@@ -0,0 +1,34 @@
+Description:
+Returns the version-control based modification time of a file.
+
+Files:
+lib/vc-mtime.h
+lib/vc-mtime.c
+
+Depends-on:
+time-h
+bool
+spawn-pipe
+wait-process
+execute
+safe-read
+error
+getline
+xstrtol
+stat-time
+gettext-h
+gnulib-i18n
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += vc-mtime.c
+
+Include:
+"vm-mtime.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible

View File

@ -0,0 +1,64 @@
From f47c5f2e21d0ccedb271b406e35b6963b23a64c4 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Wed, 30 Apr 2025 13:11:01 +0200
Subject: [PATCH] clean-temp: Fix link error (regression yesterday).
* lib/clean-temp.c: Include hashkey-string.h.
(create_temp_dir): Use hashkey_string_* functions instead of
clean_temp_string_*.
* lib/clean-temp-private.h (clean_temp_string_equals,
clean_temp_string_hash): Remove declarations.
* modules/clean-temp (Depends-on): Add hashkey-string.
---
ChangeLog | 10 ++++++++++
lib/clean-temp-private.h | 3 ---
lib/clean-temp.c | 5 +++--
modules/clean-temp | 1 +
4 files changed, 14 insertions(+), 5 deletions(-)
--- a/lib/clean-temp-private.h
+++ b/lib/clean-temp-private.h
@@ -68,9 +68,6 @@ struct closeable_fd
#define descriptors clean_temp_descriptors
extern gl_list_t /* <closeable_fd *> */ volatile descriptors;
-extern bool clean_temp_string_equals (const void *x1, const void *x2);
-extern size_t clean_temp_string_hash (const void *x);
-
extern _GL_ASYNC_SAFE int clean_temp_asyncsafe_close (struct closeable_fd *element);
extern void clean_temp_init_asyncsafe_close (void);
--- a/lib/clean-temp.c
+++ b/lib/clean-temp.c
@@ -45,6 +45,7 @@
#include "xmalloca.h"
#include "glthread/lock.h"
#include "thread-optim.h"
+#include "hashkey-string.h"
#include "gl_xlist.h"
#include "gl_linkedhash_list.h"
#include "gl_linked_list.h"
@@ -221,11 +222,11 @@ create_temp_dir (const char *prefix, con
tmpdir->cleanup_verbose = cleanup_verbose;
tmpdir->subdirs =
gl_list_create_empty (GL_LINKEDHASH_LIST,
- clean_temp_string_equals, clean_temp_string_hash,
+ hashkey_string_equals, hashkey_string_hash,
NULL, false);
tmpdir->files =
gl_list_create_empty (GL_LINKEDHASH_LIST,
- clean_temp_string_equals, clean_temp_string_hash,
+ hashkey_string_equals, hashkey_string_hash,
NULL, false);
/* Create the temporary directory. */
--- a/modules/clean-temp
+++ b/modules/clean-temp
@@ -24,6 +24,7 @@ rmdir
xalloc
xalloc-die
xmalloca
+hashkey-string
linkedhash-list
linked-list
xlist

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
From 60cd34886c2c9f509974239fcf64a61f9a507d14 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Tue, 25 Feb 2025 09:04:28 +0100
Subject: [PATCH] vc-mtime: Reduce number of read() system calls.
* lib/vc-mtime.c: Include <stddef.h>.
(git_vc_controlled): Read bytes into a buffer, not one-by-one.
---
ChangeLog | 6 ++++++
lib/vc-mtime.c | 15 +++++++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
--- a/lib/vc-mtime.c
+++ b/lib/vc-mtime.c
@@ -21,6 +21,7 @@
/* Specification. */
#include "vc-mtime.h"
+#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
@@ -56,11 +57,17 @@ git_vc_controlled (const char *filename)
return false;
/* Read the subprocess output, and test whether it is non-empty. */
- size_t count = 0;
- char c;
+ ptrdiff_t count = 0;
- while (safe_read (fd[0], &c, 1) > 0)
- count++;
+ for (;;)
+ {
+ char buf[1024];
+ ptrdiff_t n = safe_read (fd[0], buf, sizeof (buf));
+ if (n > 0)
+ count += n;
+ else
+ break;
+ }
close (fd[0]);

View File

@ -0,0 +1,968 @@
From 78269749030dde23182c29376d1410592436eb5d Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Thu, 1 May 2025 17:26:27 +0200
Subject: [PATCH] vc-mtime: Add API for more efficient use of git.
Reported by Serhii Tereshchenko, Arthur, Adam YS, Foucauld Degeorges
at <https://savannah.gnu.org/bugs/?66865>.
* lib/vc-mtime.h (max_vc_mtime): New declaration.
* lib/vc-mtime.c: Include <errno.h>, <stdio.h>, <string.h>, filename.h,
xalloc.h, xgetcwd.h, xvasprintf.h, gl_map.h, gl_xmap.h, gl_hash_map.h,
hashkey-string.h, unlocked-io.h.
(is_git_present): New function, extracted from vc_mtime.
(vc_mtime): Invoke it.
(MAX_COMMAND_LENGTH, MAX_CMD_LEN): New macros.
(abs_git_checkout): New function, based on execute_and_read_line in
lib/javacomp.c.
(ancestor_level, relativize): New functions.
(struct accumulator): New type.
(accumulate): New function.
(max_vc_mtime): New function.
(test_ancestor_level, test_relativize, main) [TEST]: New functions.
* modules/vc-mtime (Depends-on): Add filename, xalloc, xgetcwd,
canonicalize-lgpl, xvasprintf, str_startswith, map, xmap, hash-map,
hashkey-string, getdelim.
---
ChangeLog | 23 ++
lib/vc-mtime.c | 866 +++++++++++++++++++++++++++++++++++++++++++++--
lib/vc-mtime.h | 7 +
modules/vc-mtime | 11 +
4 files changed, 886 insertions(+), 21 deletions(-)
--- a/lib/vc-mtime.c
+++ b/lib/vc-mtime.c
@@ -21,8 +21,11 @@
/* Specification. */
#include "vc-mtime.h"
+#include <errno.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <error.h>
@@ -32,11 +35,51 @@
#include "safe-read.h"
#include "xstrtol.h"
#include "stat-time.h"
+#include "filename.h"
+#include "xalloc.h"
+#include "xgetcwd.h"
+#include "xvasprintf.h"
+#include "gl_map.h"
+#include "gl_xmap.h"
+#include "gl_hash_map.h"
+#include "hashkey-string.h"
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
#include "gettext.h"
#define _(msgid) dgettext ("gnulib", msgid)
+/* ========================================================================== */
+
+/* Determines whether git is present. */
+static bool
+is_git_present (void)
+{
+ static bool git_tested;
+ static bool git_present;
+
+ if (!git_tested)
+ {
+ /* Test for presence of git:
+ "git --version >/dev/null 2>/dev/null" */
+ const char *argv[3];
+ int exitstatus;
+
+ argv[0] = "git";
+ argv[1] = "--version";
+ argv[2] = NULL;
+ exitstatus = execute ("git", "git", argv, NULL, NULL,
+ false, false, true, true,
+ true, false, NULL);
+ git_present = (exitstatus == 0);
+ git_tested = true;
+ }
+
+ return git_present;
+}
+
/* Determines whether the specified file is under version control. */
static bool
git_vc_controlled (const char *filename)
@@ -178,27 +221,7 @@ git_mtime (struct timespec *mtime, const
int
vc_mtime (struct timespec *mtime, const char *filename)
{
- static bool git_tested;
- static bool git_present;
-
- if (!git_tested)
- {
- /* Test for presence of git:
- "git --version >/dev/null 2>/dev/null" */
- const char *argv[3];
- int exitstatus;
-
- argv[0] = "git";
- argv[1] = "--version";
- argv[2] = NULL;
- exitstatus = execute ("git", "git", argv, NULL, NULL,
- false, false, true, true,
- true, false, NULL);
- git_present = (exitstatus == 0);
- git_tested = true;
- }
-
- if (git_present
+ if (is_git_present ()
&& git_vc_controlled (filename)
&& git_unmodified (filename))
{
@@ -213,3 +236,804 @@ vc_mtime (struct timespec *mtime, const
}
return -1;
}
+
+/* ========================================================================== */
+
+/* Maximum length of a command that is guaranteed to work. */
+#if defined _WIN32 || defined __CYGWIN__
+/* Windows */
+# define MAX_COMMAND_LENGTH 8192
+#else
+/* Unix platforms */
+# define MAX_COMMAND_LENGTH 32768
+#endif
+/* Keep some safe distance to this maximum. */
+#define MAX_CMD_LEN ((int) (MAX_COMMAND_LENGTH * 0.8))
+
+/* Returns the directory name of the git checkout that contains tha current
+ directory, as an absolute file name, or NULL if the current directory is
+ not in a git checkout. */
+static char *
+abs_git_checkout (void)
+{
+ /* Run "git rev-parse --show-toplevel 2>/dev/null" and return its output,
+ without the trailing newline. */
+ const char *argv[4];
+ pid_t child;
+ int fd[1];
+
+ argv[0] = "git";
+ argv[1] = "rev-parse";
+ argv[2] = "--show-toplevel";
+ argv[3] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+
+ if (child == -1)
+ return NULL;
+
+ /* Retrieve its result. */
+ FILE *fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ char *line = NULL;
+ size_t linesize = 0;
+ size_t linelen = getline (&line, &linesize, fp);
+ if (linelen == (size_t)(-1))
+ {
+ fclose (fp);
+ wait_subprocess (child, "git", true, true, true, false, NULL);
+ return NULL;
+ }
+ else
+ {
+ int exitstatus;
+
+ if (linelen > 0 && line[linelen - 1] == '\n')
+ line[linelen - 1] = '\0';
+
+ /* Read until EOF (otherwise the child process may get a SIGPIPE signal). */
+ while (getc (fp) != EOF)
+ ;
+
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ exitstatus =
+ wait_subprocess (child, "git", true, true, true, false, NULL);
+ if (exitstatus == 0)
+ return line;
+ }
+ free (line);
+ return NULL;
+}
+
+/* Given an absolute canonicalized directory DIR1 and an absolute canonicalized
+ directory DIR2, returns N where DIR1 = DIR2 "/.." ... "/.." with N times
+ "/..", or -1 if DIR1 is not an ancestor directory of DIR2. */
+static long
+ancestor_level (const char *dir1, const char *dir2)
+{
+ if (strcmp (dir1, "/") == 0)
+ dir1 = "";
+ if (strcmp (dir2, "/") == 0)
+ dir2 = "";
+ size_t dir1_len = strlen (dir1);
+ if (strncmp (dir1, dir2, dir1_len) == 0)
+ {
+ /* DIR2 starts with DIR1. */
+ const char *p = dir2 + dir1_len;
+ if (*p == '\0')
+ /* DIR2 and DIR1 are the same. */
+ return 0;
+ if (ISSLASH (*p))
+ {
+ /* Return the number of slashes in the tail of DIR2 that starts
+ at P. */
+ long n = 1;
+ p++;
+ for (; *p != '\0'; p++)
+ if (ISSLASH (*p))
+ n++;
+ return n;
+ }
+ }
+ return -1;
+}
+
+/* Given an absolute canolicalized FILENAME that starts with DIR1, returns the
+ same file name relative to DIR2, where DIR1 = DIR2 "/.." ... "/.." with
+ N times "/..", as a freshly allocated string. */
+static char *
+relativize (const char *filename,
+ unsigned long n, const char *dir1, const char *dir2)
+{
+ if (strcmp (dir1, "/") == 0)
+ dir1 = "";
+ size_t dir1_len = strlen (dir1);
+ if (!(strncmp (filename, dir1, dir1_len) == 0
+ && (filename[dir1_len] == '\0' || ISSLASH (filename[dir1_len]))))
+ /* Invalid argument. */
+ abort ();
+ if (strcmp (dir2, "/") == 0)
+ dir2 = "";
+
+ dir2 += dir1_len;
+ filename += dir1_len;
+ for (;;)
+ {
+ /* Invariant: The result will be N times "../" followed by FILENAME. */
+ if (*filename == '\0')
+ break;
+ if (!ISSLASH (*filename))
+ abort ();
+ filename++;
+ if (*dir2 == '\0')
+ break;
+ if (!ISSLASH (*dir2))
+ abort ();
+ dir2++;
+ /* Skip one component in DIR2. */
+ const char *dir2_s;
+ for (dir2_s = dir2; *dir2_s != '\0'; dir2_s++)
+ if (ISSLASH (*dir2_s))
+ break;
+ /* Skip one component in FILENAME, at P. */
+ const char *filename_s;
+ for (filename_s = filename; *filename_s != '\0'; filename_s++)
+ if (ISSLASH (*filename_s))
+ break;
+ /* Did the components match? */
+ if (!(filename_s - filename == dir2_s - dir2
+ && memcmp (filename, dir2, dir2_s - dir2) == 0))
+ break;
+ dir2 = dir2_s;
+ filename = filename_s;
+ n--;
+ }
+
+ if (n == 0 && *filename == '\0')
+ return xstrdup (".");
+
+ char *result = (char *) xmalloc (3 * n + strlen (filename) + 1);
+ {
+ char *q = result;
+ for (; n > 0; n--)
+ {
+ q[0] = '.'; q[1] = '.'; q[2] = '/'; q += 3;
+ }
+ strcpy (q, filename);
+ }
+ return result;
+}
+
+/* Accumulating mtimes. */
+struct accumulator
+{
+ bool has_some_mtimes;
+ struct timespec max_of_mtimes;
+};
+
+static void
+accumulate (struct accumulator *accu, struct timespec mtime)
+{
+ if (accu->has_some_mtimes)
+ {
+ /* Compute the maximum of accu->max_of_mtimes and mtime. */
+ if (accu->max_of_mtimes.tv_sec < mtime.tv_sec
+ || (accu->max_of_mtimes.tv_sec == mtime.tv_sec
+ && accu->max_of_mtimes.tv_nsec < mtime.tv_nsec))
+ accu->max_of_mtimes = mtime;
+ }
+ else
+ {
+ accu->max_of_mtimes = mtime;
+ accu->has_some_mtimes = true;
+ }
+}
+
+int
+max_vc_mtime (struct timespec *max_of_mtimes,
+ size_t nfiles, const char * const *filenames)
+{
+ if (nfiles == 0)
+ /* Invalid argument. */
+ abort ();
+
+ struct accumulator accu = { false };
+
+ /* Determine which of the specified files are under version control,
+ and which are duplicates. (The case of duplicates is rare, but it needs
+ special attention, because 'git ls-files' eliminates duplicates.)
+ vc_controlled[n] = 1 means that filenames[n] is under version control.
+ vc_controlled[n] = 0 means that filenames[n] is not under version control.
+ vc_controlled[n] = -1 means that filenames[n] is a duplicate. */
+ signed char *vc_controlled = XNMALLOC (nfiles, signed char);
+ for (size_t n = 0; n < nfiles; n++)
+ vc_controlled[n] = 0;
+
+ if (is_git_present ())
+ {
+ /* Since 'git ls-files' produces an error when at least one of the files
+ is outside the git checkout that contains tha current directory, we
+ need to filter out such files. This is most easily done by converting
+ each file name to a canonical file name first and then comparing with
+ the directory name of said git checkout. */
+ char *git_checkout = abs_git_checkout ();
+ if (git_checkout != NULL)
+ {
+ char *currdir = xgetcwd ();
+ /* git_checkout is expected to be an ancestor directory of the
+ current directory. */
+ long ancestor = ancestor_level (git_checkout, currdir);
+ if (ancestor >= 0)
+ {
+ char **canonical_filenames = XNMALLOC (nfiles, char *);
+ for (size_t n = 0; n < nfiles; n++)
+ {
+ char *canonical = canonicalize_file_name (filenames[n]);
+ if (canonical == NULL)
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+ /* The file filenames[n] does not exist. */
+ for (size_t k = n; k > 0; )
+ free (canonical_filenames[--k]);
+ free (canonical_filenames);
+ free (currdir);
+ free (git_checkout);
+ free (vc_controlled);
+ return -1;
+ }
+ canonical_filenames[n] = canonical;
+ }
+
+ /* Test which of these absolute file names are outside of the
+ git_checkout. */
+ char *git_checkout_slash =
+ (strcmp (git_checkout, "/") == 0
+ ? xstrdup (git_checkout)
+ : xasprintf ("%s/", git_checkout));
+
+ char **checkout_relative_filenames = XNMALLOC (nfiles, char *);
+ char **currdir_relative_filenames = XNMALLOC (nfiles, char *);
+ for (size_t n = 0; n < nfiles; n++)
+ {
+ if (str_startswith (canonical_filenames[n], git_checkout_slash))
+ {
+ vc_controlled[n] = 1;
+ checkout_relative_filenames[n] =
+ relativize (canonical_filenames[n],
+ 0, git_checkout, git_checkout);
+ currdir_relative_filenames[n] =
+ relativize (canonical_filenames[n],
+ ancestor, git_checkout, currdir);
+ }
+ else
+ {
+ vc_controlled[n] = 0;
+ checkout_relative_filenames[n] = NULL;
+ currdir_relative_filenames[n] = NULL;
+ }
+ }
+
+ /* Room for passing arguments to git commands. */
+ const char **argv = XNMALLOC (6 + nfiles + 1, const char *);
+
+ {
+ /* Put the relative file names into a hash table. This is needed
+ because 'git ls-files' returns the files in a different order
+ than the one we provide in the command. */
+ gl_map_t relative_filenames_ht =
+ gl_map_create_empty (GL_HASH_MAP,
+ hashkey_string_equals, hashkey_string_hash,
+ NULL, NULL);
+ for (size_t n = 0; n < nfiles; n++)
+ if (currdir_relative_filenames[n] != NULL)
+ {
+ if (gl_map_get (relative_filenames_ht, currdir_relative_filenames[n]) != NULL)
+ {
+ /* It's already in the table. */
+ vc_controlled[n] = -1;
+ }
+ else
+ gl_map_put (relative_filenames_ht, currdir_relative_filenames[n], &vc_controlled[n]);
+ }
+
+ /* Run "git ls-files -c -o -t -z FILE1..." for as many files as
+ possible, and inspect the output. */
+ size_t n0 = 0;
+ do
+ {
+ size_t i = 0;
+ argv[i++] = "git";
+ argv[i++] = "ls-files";
+ argv[i++] = "-c";
+ argv[i++] = "-o";
+ argv[i++] = "-t";
+ argv[i++] = "-z";
+ size_t i0 = i;
+
+ size_t n = n0;
+ size_t cmd_len = 25;
+ for (; n < nfiles; n++)
+ {
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
+ n++;
+ }
+ if (i > i0)
+ {
+ pid_t child;
+ int fd[1];
+
+ argv[i] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ break;
+
+ /* Read the subprocess output. It is expected to be of the form
+ T1 <space> <currdir_relative_filename1> NUL
+ T2 <space> <currdir_relative_filename2> NUL
+ ...
+ where the relative filenames correspond to the given file
+ names (because we have already relativized them). */
+ FILE *fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ char *fn = NULL;
+ size_t fn_size = 0;
+ for (;;)
+ {
+ int status = fgetc (fp);
+ if (status == EOF)
+ break;
+ /* status is a status tag, as documented in
+ "man git-ls-files". */
+
+ int space = fgetc (fp);
+ if (space != ' ')
+ {
+ fprintf (stderr, "vc-mtime: git ls-files output not as expected\n");
+ break;
+ }
+
+ if (getdelim (&fn, &fn_size, '\0', fp) == -1)
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+ fprintf (stderr, "vc-mtime: failed to read git ls-files output\n");
+ break;
+ }
+ signed char *vc_controlled_p =
+ (signed char *) gl_map_get (relative_filenames_ht, fn);
+ if (vc_controlled_p == NULL)
+ fprintf (stderr, "vc-mtime: git ls-files returned an unexpected file name: %s\n", fn);
+ else
+ *vc_controlled_p = (status == 'H' ? 1 : 0);
+ }
+
+ free (fn);
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ int exitstatus =
+ wait_subprocess (child, "git", false, true, true, false, NULL);
+ if (exitstatus != 0)
+ fprintf (stderr, "vc-mtime: git ls-files failed with exit code %d\n", exitstatus);
+ }
+ n0 = n;
+ }
+ while (n0 < nfiles);
+
+ gl_map_free (relative_filenames_ht);
+ }
+
+ {
+ /* Put the relative file names into a hash table. This is needed
+ because 'git diff' returns the files in a different order
+ than the one we provide in the command. */
+ gl_map_t relative_filenames_ht =
+ gl_map_create_empty (GL_HASH_MAP,
+ hashkey_string_equals, hashkey_string_hash,
+ NULL, NULL);
+ for (size_t n = 0; n < nfiles; n++)
+ if (vc_controlled[n] == 1)
+ {
+ /* No need to test for duplicates here. We have already set
+ vc_controlled[n] to -1 for duplicates, above. */
+ gl_map_put (relative_filenames_ht, checkout_relative_filenames[n], &vc_controlled[n]);
+ }
+
+ /* Run "git diff --name-only --no-relative -z HEAD -- FILE1..." for
+ as many files as possible, and inspect the output. */
+ size_t n0 = 0;
+ do
+ {
+ size_t i = 0;
+ argv[i++] = "git";
+ argv[i++] = "diff";
+ argv[i++] = "--name-only";
+ argv[i++] = "--no-relative";
+ argv[i++] = "-z";
+ argv[i++] = "HEAD";
+ argv[i++] = "--";
+ size_t i0 = i;
+
+ size_t n = n0;
+ size_t cmd_len = 46;
+ for (; n < nfiles; n++)
+ {
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
+ n++;
+ }
+ if (i > i0)
+ {
+ pid_t child;
+ int fd[1];
+
+ argv[i] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ break;
+
+ /* Read the subprocess output. It is expected to be of the form
+ <checkout_relative_filename1> NUL
+ <checkout_relative_filename2> NUL
+ ...
+ where the relative filenames are relative to the git
+ checkout dir, not to currdir! */
+ FILE *fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ char *fn = NULL;
+ size_t fn_size = 0;
+ for (;;)
+ {
+ /* Test for EOF. */
+ int c = fgetc (fp);
+ if (c == EOF)
+ break;
+ ungetc (c, fp);
+
+ if (getdelim (&fn, &fn_size, '\0', fp) == -1)
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+ fprintf (stderr, "vc-mtime: failed to read git diff output\n");
+ break;
+ }
+ signed char *vc_controlled_p =
+ (signed char *) gl_map_get (relative_filenames_ht, fn);
+ if (vc_controlled_p == NULL)
+ fprintf (stderr, "vc-mtime: git diff returned an unexpected file name: %s\n", fn);
+ else
+ /* filenames[n] is under version control but is modified.
+ Treat it like a file not under version control. */
+ *vc_controlled_p = 0;
+ }
+
+ free (fn);
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ int exitstatus =
+ wait_subprocess (child, "git", false, true, true, false, NULL);
+ if (exitstatus != 0)
+ fprintf (stderr, "vc-mtime: git diff failed with exit code %d\n", exitstatus);
+ }
+ n0 = n;
+ }
+ while (n0 < nfiles);
+
+ gl_map_free (relative_filenames_ht);
+ }
+
+ {
+ /* Run "git log -1 --format=%ct -- FILE1...". It prints the
+ time of last modification (the 'CommitDate', not the
+ 'AuthorDate' which merely represents the time at which the
+ author locally committed the first version of the change),
+ as the number of seconds since the Epoch. The '--' option
+ is for the case that the specified file was removed. */
+ size_t n0 = 0;
+ do
+ {
+ size_t i = 0;
+ argv[i++] = "git";
+ argv[i++] = "log";
+ argv[i++] = "-1";
+ argv[i++] = "--format=%ct";
+ argv[i++] = "--";
+ size_t i0 = i;
+
+ size_t n = n0;
+ size_t cmd_len = 27;
+ for (; n < nfiles; n++)
+ {
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
+ n++;
+ }
+ if (i > i0)
+ {
+ pid_t child;
+ int fd[1];
+
+ argv[i] = NULL;
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ break;
+
+ /* Read the subprocess output. It is expected to be a
+ single line, containing a positive integer. */
+ FILE *fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ char *line = NULL;
+ size_t linesize = 0;
+ size_t linelen = getline (&line, &linesize, fp);
+ if (linelen == (size_t)(-1))
+ {
+ if (errno == ENOMEM)
+ xalloc_die ();
+ fprintf (stderr, "vc-mtime: failed to read git log output\n");
+ git_log_fail1:
+ free (line);
+ fclose (fp);
+ wait_subprocess (child, "git", true, false, true, false, NULL);
+ git_log_fail2:
+ free (argv);
+ for (size_t k = nfiles; k > 0; )
+ free (currdir_relative_filenames[--k]);
+ free (currdir_relative_filenames);
+ for (size_t k = nfiles; k > 0; )
+ free (checkout_relative_filenames[--k]);
+ free (checkout_relative_filenames);
+ free (git_checkout_slash);
+ for (size_t k = nfiles; k > 0; )
+ free (canonical_filenames[--k]);
+ free (canonical_filenames);
+ free (currdir);
+ free (git_checkout);
+ free (vc_controlled);
+ return -1;
+ }
+ if (linelen > 0 && line[linelen - 1] == '\n')
+ line[linelen - 1] = '\0';
+
+ char *endptr;
+ unsigned long git_log_time;
+ if (!(xstrtoul (line, &endptr, 10, &git_log_time, NULL) == LONGINT_OK
+ && endptr == line + strlen (line)))
+ {
+ fprintf (stderr, "vc-mtime: git log output not as expected\n");
+ goto git_log_fail1;
+ }
+
+ struct timespec mtime;
+ mtime.tv_sec = git_log_time;
+ mtime.tv_nsec = 0;
+ accumulate (&accu, mtime);
+
+ free (line);
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit status. */
+ int exitstatus =
+ wait_subprocess (child, "git", false, true, true, false, NULL);
+ if (exitstatus != 0)
+ {
+ fprintf (stderr, "vc-mtime: git log failed with exit code %d\n", exitstatus);
+ goto git_log_fail2;
+ }
+ }
+ n0 = n;
+ }
+ while (n0 < nfiles);
+ }
+
+ free (argv);
+ for (size_t k = nfiles; k > 0; )
+ free (currdir_relative_filenames[--k]);
+ free (currdir_relative_filenames);
+ for (size_t k = nfiles; k > 0; )
+ free (checkout_relative_filenames[--k]);
+ free (checkout_relative_filenames);
+ free (git_checkout_slash);
+ for (size_t k = nfiles; k > 0; )
+ free (canonical_filenames[--k]);
+ free (canonical_filenames);
+ }
+ free (currdir);
+ }
+ free (git_checkout);
+ }
+
+ /* For the files that are not under version control, or that are modified
+ compared to HEAD, use the file's time stamp. */
+ for (size_t n = 0; n < nfiles; n++)
+ if (vc_controlled[n] == 0)
+ {
+ struct stat statbuf;
+ if (stat (filenames[n], &statbuf) < 0)
+ {
+ free (vc_controlled);
+ return -1;
+ }
+
+ struct timespec mtime = get_stat_mtime (&statbuf);
+ accumulate (&accu, mtime);
+ }
+
+ free (vc_controlled);
+
+ /* Since nfiles > 0, we must have accumulated at least one mtime. */
+ if (!accu.has_some_mtimes)
+ abort ();
+ *max_of_mtimes = accu.max_of_mtimes;
+ return 0;
+}
+
+/* ========================================================================== */
+
+#ifdef TEST
+
+#include <assert.h>
+#include <stdio.h>
+#include <time.h>
+
+/* Some unit tests for internal functions. */
+
+static void
+test_ancestor_level (void)
+{
+ assert (ancestor_level ("/home/user/projects/gnulib", "/home/user/projects/gnulib") == 0);
+ assert (ancestor_level ("/", "/") == 0);
+
+ assert (ancestor_level ("/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto") == 2);
+ assert (ancestor_level ("/", "/home/user") == 2);
+
+ assert (ancestor_level ("/home/user/.local", "/home/user/projects/gnulib") == -1);
+ assert (ancestor_level ("/.local", "/home/user") == -1);
+ assert (ancestor_level ("/.local", "/") == -1);
+}
+
+static void
+test_relativize (void)
+{
+ assert (strcmp (relativize ("/home/user/projects/gnulib",
+ 0, "/home/user/projects/gnulib", "/home/user/projects/gnulib"),
+ ".") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/NEWS",
+ 0, "/home/user/projects/gnulib", "/home/user/projects/gnulib"),
+ "NEWS") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/doc/Makefile",
+ 0, "/home/user/projects/gnulib", "/home/user/projects/gnulib"),
+ "doc/Makefile") == 0);
+
+ assert (strcmp (relativize ("/",
+ 0, "/", "/"),
+ ".") == 0);
+ assert (strcmp (relativize ("/swapfile",
+ 0, "/", "/"),
+ "swapfile") == 0);
+ assert (strcmp (relativize ("/etc/passwd",
+ 0, "/", "/"),
+ "etc/passwd") == 0);
+
+ assert (strcmp (relativize ("/home/user/projects/gnulib",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../../") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/lib",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/lib/crypto",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ ".") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/lib/malloc",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../malloc") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/lib/cr",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../cr") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/lib/cryptography",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../cryptography") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/doc",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../../doc") == 0);
+ assert (strcmp (relativize ("/home/user/projects/gnulib/doc/Makefile",
+ 2, "/home/user/projects/gnulib", "/home/user/projects/gnulib/lib/crypto"),
+ "../../doc/Makefile") == 0);
+
+ assert (strcmp (relativize ("/",
+ 2, "/", "/home/user"),
+ "../../") == 0);
+ assert (strcmp (relativize ("/home",
+ 2, "/", "/home/user"),
+ "../") == 0);
+ assert (strcmp (relativize ("/home/user",
+ 2, "/", "/home/user"),
+ ".") == 0);
+ assert (strcmp (relativize ("/home/root",
+ 2, "/", "/home/user"),
+ "../root") == 0);
+ assert (strcmp (relativize ("/home/us",
+ 2, "/", "/home/user"),
+ "../us") == 0);
+ assert (strcmp (relativize ("/home/users",
+ 2, "/", "/home/user"),
+ "../users") == 0);
+ assert (strcmp (relativize ("/etc",
+ 2, "/", "/home/user"),
+ "../../etc") == 0);
+ assert (strcmp (relativize ("/etc/passwd",
+ 2, "/", "/home/user"),
+ "../../etc/passwd") == 0);
+}
+
+/* Usage: ./a.out FILE[...]
+ */
+int
+main (int argc, char *argv[])
+{
+ test_ancestor_level ();
+ test_relativize ();
+
+ if (argc == 1)
+ {
+ fprintf (stderr, "Usage: ./a.out FILE[...]\n");
+ return 1;
+ }
+ struct timespec mtime;
+ int ret = max_vc_mtime (&mtime, argc - 1, (const char **) argv + 1);
+ if (ret == 0)
+ {
+ time_t t = mtime.tv_sec;
+ struct tm *gmt = gmtime (&t);
+ printf ("mtime = %04d-%02d-%02d %02d:%02d:%02d UTC\n",
+ gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
+ gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
+ return 0;
+ }
+ else
+ {
+ printf ("failed\n");
+ return 1;
+ }
+}
+
+/*
+ * Local Variables:
+ * compile-command: "gcc -ggdb -DTEST -Wall -I. -I.. vc-mtime.c libgnu.a"
+ * End:
+ */
+
+#endif
--- a/lib/vc-mtime.h
+++ b/lib/vc-mtime.h
@@ -90,6 +90,13 @@ extern "C" {
Upon failure, it returns -1. */
extern int vc_mtime (struct timespec *mtime, const char *filename);
+/* Determines the maximum of the version-controlled modification times of
+ FILENAMES[0..NFILES-1], and returns 0.
+ Upon failure, it returns -1.
+ NFILES must be > 0. */
+extern int max_vc_mtime (struct timespec *max_of_mtimes,
+ size_t nfiles, const char * const *filenames);
+
#ifdef __cplusplus
}
#endif
--- a/modules/vc-mtime
+++ b/modules/vc-mtime
@@ -16,6 +16,17 @@ error
getline
xstrtol
stat-time
+filename
+xalloc
+xgetcwd
+canonicalize-lgpl
+xvasprintf
+str_startswith
+map
+xmap
+hash-map
+hashkey-string
+getdelim
gettext-h
gnulib-i18n

View File

@ -0,0 +1,91 @@
From f4c40c2d6aabef8e587176bbf5226c8bc6649574 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 2 May 2025 02:43:23 +0200
Subject: [PATCH] vc-mtime: Add API for more efficient use of git, part 2.
* lib/vc-mtime.c (max_vc_mtime): Don't skip the odd-numbered arguments.
---
ChangeLog | 5 +++++
lib/vc-mtime.c | 57 +++++++++++++++++++++-----------------------------
2 files changed, 29 insertions(+), 33 deletions(-)
--- a/lib/vc-mtime.c
+++ b/lib/vc-mtime.c
@@ -558,17 +558,14 @@ max_vc_mtime (struct timespec *max_of_mt
size_t n = n0;
size_t cmd_len = 25;
for (; n < nfiles; n++)
- {
- if (vc_controlled[n] == 1)
- {
- if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
- && i > i0)
- break;
- argv[i++] = currdir_relative_filenames[n];
- cmd_len += 1 + strlen (currdir_relative_filenames[n]);
- }
- n++;
- }
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
if (i > i0)
{
pid_t child;
@@ -672,17 +669,14 @@ max_vc_mtime (struct timespec *max_of_mt
size_t n = n0;
size_t cmd_len = 46;
for (; n < nfiles; n++)
- {
- if (vc_controlled[n] == 1)
- {
- if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
- && i > i0)
- break;
- argv[i++] = currdir_relative_filenames[n];
- cmd_len += 1 + strlen (currdir_relative_filenames[n]);
- }
- n++;
- }
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
if (i > i0)
{
pid_t child;
@@ -768,17 +762,14 @@ max_vc_mtime (struct timespec *max_of_mt
size_t n = n0;
size_t cmd_len = 27;
for (; n < nfiles; n++)
- {
- if (vc_controlled[n] == 1)
- {
- if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
- && i > i0)
- break;
- argv[i++] = currdir_relative_filenames[n];
- cmd_len += 1 + strlen (currdir_relative_filenames[n]);
- }
- n++;
- }
+ if (vc_controlled[n] == 1)
+ {
+ if (cmd_len + strlen (currdir_relative_filenames[n]) >= MAX_CMD_LEN
+ && i > i0)
+ break;
+ argv[i++] = currdir_relative_filenames[n];
+ cmd_len += 1 + strlen (currdir_relative_filenames[n]);
+ }
if (i > i0)
{
pid_t child;

View File

@ -0,0 +1,125 @@
From 47548a77525a0f4489c9c420ccc2159079365da8 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 2 May 2025 12:09:40 +0200
Subject: [PATCH] vc-mtime: Make it work with git versions < 2.28.
* lib/vc-mtime.c (git_version): New variable.
(is_git_present): Read the output of "git --version", and set
git_version.
(max_vc_mtime): Don't pass option --no-relative if the git version
is < 2.28.
---
ChangeLog | 9 ++++++
lib/vc-mtime.c | 82 +++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 83 insertions(+), 8 deletions(-)
--- a/lib/vc-mtime.c
+++ b/lib/vc-mtime.c
@@ -53,7 +53,9 @@
/* ========================================================================== */
-/* Determines whether git is present. */
+static const char *git_version;
+
+/* Determines whether git is present, and sets git_version if so. */
static bool
is_git_present (void)
{
@@ -63,17 +65,67 @@ is_git_present (void)
if (!git_tested)
{
/* Test for presence of git:
- "git --version >/dev/null 2>/dev/null" */
+ "git --version 2>/dev/null" */
const char *argv[3];
- int exitstatus;
+ pid_t child;
+ int fd[1];
argv[0] = "git";
argv[1] = "--version";
argv[2] = NULL;
- exitstatus = execute ("git", "git", argv, NULL, NULL,
- false, false, true, true,
- true, false, NULL);
- git_present = (exitstatus == 0);
+ child = create_pipe_in ("git", "git", argv, NULL, NULL,
+ DEV_NULL, true, true, false, fd);
+ if (child == -1)
+ git_present = false;
+ else
+ {
+ /* Retrieve its result. */
+ FILE *fp = fdopen (fd[0], "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("fdopen() failed"));
+
+ char *line = NULL;
+ size_t linesize = 0;
+ size_t linelen = getline (&line, &linesize, fp);
+ if (linelen == (size_t)(-1))
+ {
+ fclose (fp);
+ wait_subprocess (child, "git", true, true, true, false, NULL);
+ git_present = false;
+ }
+ else
+ {
+ if (linelen > 0 && line[linelen - 1] == '\n')
+ line[linelen - 1] = '\0';
+
+ /* Read until EOF (otherwise the child process may get a SIGPIPE
+ signal). */
+ while (getc (fp) != EOF)
+ ;
+
+ fclose (fp);
+
+ /* Remove zombie process from process list, and retrieve exit
+ status. */
+ int exitstatus =
+ wait_subprocess (child, "git", true, true, true, false, NULL);
+ if (exitstatus != 0)
+ {
+ free (line);
+ git_present = false;
+ }
+ else
+ {
+ /* The version starts at the first digit in the line. */
+ const char *p = line;
+ for (; *p != '0'; p++)
+ if (*p >= '0' && *p <= '9')
+ break;
+ git_version = p;
+ git_present = true;
+ }
+ }
+ }
git_tested = true;
}
@@ -660,7 +712,21 @@ max_vc_mtime (struct timespec *max_of_mt
argv[i++] = "git";
argv[i++] = "diff";
argv[i++] = "--name-only";
- argv[i++] = "--no-relative";
+ /* With git versions >= 2.28, we pass option --no-relative,
+ in order to neutralize any possible customization of the
+ "diff.relative" property. With git versions < 2.28, this
+ is not needed, and the option --no-relative does not
+ exist. */
+ if (!(git_version[0] <= '1'
+ || (git_version[0] == '2' && git_version[1] == '.'
+ && ((git_version[2] >= '0' && git_version[2] <= '9'
+ && !(git_version[3] >= '0' && git_version[3] <= '9'))
+ || (((git_version[2] == '1'
+ && git_version[3] >= '0' && git_version[3] <= '9')
+ || (git_version[2] == '2'
+ && git_version[3] >= '0' && git_version[3] <= '7'))
+ && !(git_version[4] >= '0' && git_version[4] <= '9'))))))
+ argv[i++] = "--no-relative";
argv[i++] = "-z";
argv[i++] = "HEAD";
argv[i++] = "--";

View File

@ -0,0 +1,117 @@
From 24010120fab36721caaf92be076655571e44da07 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 3 Jan 2025 09:26:14 +0100
Subject: [PATCH] str_startswith: New module.
* lib/string.in.h (str_startswith): New declaration.
* lib/str_startswith.c: New file.
* m4/string_h.m4 (gl_STRING_H_REQUIRE_DEFAULTS): Initialize
GNULIB_STR_STARTSWITH.
* modules/string-h (Makefile.am): Substitute GNULIB_STR_STARTSWITH.
* modules/str_startswith: New file.
---
ChangeLog | 10 ++++++++++
lib/str_startswith.c | 29 +++++++++++++++++++++++++++++
lib/string.in.h | 8 ++++++++
m4/string_h.m4 | 3 ++-
modules/str_startswith | 23 +++++++++++++++++++++++
modules/string-h | 1 +
6 files changed, 73 insertions(+), 1 deletion(-)
create mode 100644 lib/str_startswith.c
create mode 100644 modules/str_startswith
--- /dev/null
+++ b/lib/str_startswith.c
@@ -0,0 +1,29 @@
+/* str_startswith function.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
+
+#include "config.h"
+
+/* Specification. */
+#include <string.h>
+
+
+int
+str_startswith (const char *string, const char *prefix)
+{
+ return strncmp (string, prefix, strlen (prefix)) == 0;
+}
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1079,6 +1079,14 @@ _GL_WARN_ON_USE (strtok_r, "strtok_r is
/* The following functions are not specified by POSIX. They are gnulib
extensions. */
+#if @GNULIB_STR_STARTSWITH@
+/* Returns true if STRING starts with PREFIX.
+ Returns false otherwise. */
+_GL_EXTERN_C int str_startswith (const char *string, const char *prefix)
+ _GL_ATTRIBUTE_PURE
+ _GL_ARG_NONNULL ((1, 2));
+#endif
+
#if @GNULIB_MBSLEN@
/* Return the number of multibyte characters in the character string STRING.
This considers multibyte characters, unlike strlen, which counts bytes. */
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -70,6 +70,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSTR])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASESTR])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOK_R])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STR_STARTSWITH])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSLEN])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNLEN])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCHR])
--- /dev/null
+++ b/modules/str_startswith
@@ -0,0 +1,23 @@
+Description:
+str_startswith() function: test whether a string starts with a given prefix.
+
+Files:
+lib/str_startswith.c
+
+Depends-on:
+string-h
+
+configure.ac:
+gl_STRING_MODULE_INDICATOR([str_startswith])
+
+Makefile.am:
+lib_SOURCES += str_startswith.c
+
+Include:
+<string.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--- a/modules/string-h
+++ b/modules/string-h
@@ -69,6 +69,7 @@ string.h: string.in.h $(top_builddir)/co
-e 's/@''GNULIB_STRSTR''@/$(GNULIB_STRSTR)/g' \
-e 's/@''GNULIB_STRCASESTR''@/$(GNULIB_STRCASESTR)/g' \
-e 's/@''GNULIB_STRTOK_R''@/$(GNULIB_STRTOK_R)/g' \
+ -e 's/@''GNULIB_STR_STARTSWITH''@/$(GNULIB_STR_STARTSWITH)/g' \
-e 's/@''GNULIB_STRERROR''@/$(GNULIB_STRERROR)/g' \
-e 's/@''GNULIB_STRERROR_R''@/$(GNULIB_STRERROR_R)/g' \
-e 's/@''GNULIB_STRERRORNAME_NP''@/$(GNULIB_STRERRORNAME_NP)/g' \

View File

@ -0,0 +1,119 @@
From d89ac9373d9748f7601babf52c9129fcbcf0c907 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 3 Jan 2025 09:54:14 +0100
Subject: [PATCH] str_endswith: New module.
* lib/string.in.h (str_endswith): New declaration.
* lib/str_endswith.c: New file.
* m4/string_h.m4 (gl_STRING_H_REQUIRE_DEFAULTS): Initialize
GNULIB_STR_ENDSWITH.
* modules/string-h (Makefile.am): Substitute GNULIB_STR_ENDSWITH.
* modules/str_endswith: New file.
---
ChangeLog | 10 ++++++++++
lib/str_endswith.c | 31 +++++++++++++++++++++++++++++++
lib/string.in.h | 8 ++++++++
m4/string_h.m4 | 3 ++-
modules/str_endswith | 23 +++++++++++++++++++++++
modules/string-h | 1 +
6 files changed, 75 insertions(+), 1 deletion(-)
create mode 100644 lib/str_endswith.c
create mode 100644 modules/str_endswith
--- /dev/null
+++ b/lib/str_endswith.c
@@ -0,0 +1,31 @@
+/* str_endswith function.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
+
+#include "config.h"
+
+/* Specification. */
+#include <string.h>
+
+
+int
+str_endswith (const char *string, const char *suffix)
+{
+ size_t len = strlen (string);
+ size_t n = strlen (suffix);
+ return len >= n && strcmp (string + len - n, suffix) == 0;
+}
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1087,6 +1087,14 @@ _GL_EXTERN_C int str_startswith (const c
_GL_ARG_NONNULL ((1, 2));
#endif
+#if @GNULIB_STR_ENDSWITH@
+/* Returns true if STRING ends with SUFFIX.
+ Returns false otherwise. */
+_GL_EXTERN_C int str_endswith (const char *string, const char *prefix)
+ _GL_ATTRIBUTE_PURE
+ _GL_ARG_NONNULL ((1, 2));
+#endif
+
#if @GNULIB_MBSLEN@
/* Return the number of multibyte characters in the character string STRING.
This considers multibyte characters, unlike strlen, which counts bytes. */
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -71,6 +71,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASESTR])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOK_R])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STR_STARTSWITH])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STR_ENDSWITH])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSLEN])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNLEN])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCHR])
--- /dev/null
+++ b/modules/str_endswith
@@ -0,0 +1,23 @@
+Description:
+str_endswith() function: test whether a string ends with a given suffix.
+
+Files:
+lib/str_endswith.c
+
+Depends-on:
+string-h
+
+configure.ac:
+gl_STRING_MODULE_INDICATOR([str_endswith])
+
+Makefile.am:
+lib_SOURCES += str_endswith.c
+
+Include:
+<string.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--- a/modules/string-h
+++ b/modules/string-h
@@ -69,6 +69,7 @@ string.h: string.in.h $(top_builddir)/co
-e 's/@''GNULIB_STRSTR''@/$(GNULIB_STRSTR)/g' \
-e 's/@''GNULIB_STRCASESTR''@/$(GNULIB_STRCASESTR)/g' \
-e 's/@''GNULIB_STRTOK_R''@/$(GNULIB_STRTOK_R)/g' \
+ -e 's/@''GNULIB_STR_ENDSWITH''@/$(GNULIB_STR_ENDSWITH)/g' \
-e 's/@''GNULIB_STR_STARTSWITH''@/$(GNULIB_STR_STARTSWITH)/g' \
-e 's/@''GNULIB_STRERROR''@/$(GNULIB_STRERROR)/g' \
-e 's/@''GNULIB_STRERROR_R''@/$(GNULIB_STRERROR_R)/g' \

View File

@ -14,8 +14,6 @@ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
PKG_HASH:=da8ebb2ce4dcf46b90098daf962cffa68f4b4f62ea60f798d0ef12929ede6adf
HOST_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/host-build.mk
export GNULIB_SRCDIR:=$(HOST_GNULIB_SRCDIR)
@ -23,6 +21,10 @@ export GNULIB_SRCDIR:=$(HOST_GNULIB_SRCDIR)
HOST_CONFIGURE_VARS += \
lt_cv_sys_dlsearch_path=""
HOST_MAKE_FLAGS += \
am__CONFIG_DISTCLEAN_FILES= \
CONFIG_STATUS_DEPENDENCIES=
define Host/Bootstrap
( \
cd $(HOST_BUILD_DIR); \
@ -45,6 +47,7 @@ endef
define Host/Configure
$(if $(QUILT),$(call Host/Bootstrap))
$(call Host/Configure/Default)
$(call Host/Uninstall)
endef
define Host/Install
@ -54,6 +57,7 @@ endef
define Host/Uninstall
-$(call Host/Compile/Default,uninstall)
-$(call Host/Compile/Default,maintainer-clean) # Clean bootstrap files from the release
(cd $(STAGING_DIR_HOST)/share/aclocal/ && rm -f libtool.m4 ltdl.m4 lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4)
endef

View File

@ -0,0 +1,13 @@
--- a/libuuid/src/uuid.h
+++ b/libuuid/src/uuid.h
@@ -35,6 +35,10 @@
#ifndef _UL_LIBUUID_UUID_H
#define _UL_LIBUUID_UUID_H
+#if defined(__clang__) && defined(__APPLE__)
+#include_next <uuid/uuid.h>
+#endif
+
#include <sys/types.h>
#ifndef _WIN32
#include <sys/time.h>