Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libfilezilla for openSUSE:Factory checked in at 2026-06-12 19:29:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libfilezilla (Old) and /work/SRC/openSUSE:Factory/.libfilezilla.new.1981 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libfilezilla" Fri Jun 12 19:29:55 2026 rev:67 rq:1358980 version:0.56.1 Changes: -------- --- /work/SRC/openSUSE:Factory/libfilezilla/libfilezilla.changes 2026-06-02 16:11:03.263623448 +0200 +++ /work/SRC/openSUSE:Factory/.libfilezilla.new.1981/libfilezilla.changes 2026-06-12 19:31:34.948333433 +0200 @@ -2 +2,9 @@ -Tue Jun 2 10:43:25 UTC 2026 - ecsos <[email protected]> 0.56.0 +Fri Jun 12 12:46:25 UTC 2026 - ecsos <[email protected]> - 0.56.1 + +- Update to 0.56.1 + * Bugfixes and minor changes: + - macOS: Fix fz::socket::connect() failing after bind() + - Creation flag validation and normalization for fz::file + +------------------------------------------------------------------- +Tue Jun 2 10:43:25 UTC 2026 - ecsos <[email protected]> - 0.56.0 Old: ---- libfilezilla-0.56.0.tar.xz New: ---- libfilezilla-0.56.1.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libfilezilla.spec ++++++ --- /var/tmp/diff_new_pack.X5Evgn/_old 2026-06-12 19:31:37.484439291 +0200 +++ /var/tmp/diff_new_pack.X5Evgn/_new 2026-06-12 19:31:37.492439625 +0200 @@ -20,7 +20,7 @@ %define libname %{name}%{major} %define develname %{name}-devel Name: libfilezilla -Version: 0.56.0 +Version: 0.56.1 Release: 0 Summary: C++ library for filezilla License: GPL-2.0-or-later ++++++ libfilezilla-0.56.0.tar.xz -> libfilezilla-0.56.1.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/Makefile.in new/libfilezilla-0.56.1/Makefile.in --- old/libfilezilla-0.56.0/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -108,7 +108,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/NEWS new/libfilezilla-0.56.1/NEWS --- old/libfilezilla-0.56.0/NEWS 2026-05-28 11:09:15.000000000 +0200 +++ new/libfilezilla-0.56.1/NEWS 2026-06-04 11:06:23.000000000 +0200 @@ -1,3 +1,8 @@ +0.56.1 (2026-06-04) + +- macOS: Fix fz::socket::connect() failing after bind() +- Creation flag validation and normalization for fz::file + 0.56.0 (2026-05-27) + event_loop timers are now processed in a round-robin fashion if there are multiple expired timers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/aclocal.m4 new/libfilezilla-0.56.1/aclocal.m4 --- old/libfilezilla-0.56.0/aclocal.m4 2026-05-28 11:09:21.000000000 +0200 +++ new/libfilezilla-0.56.1/aclocal.m4 2026-06-04 11:06:25.000000000 +0200 @@ -1322,7 +1322,6 @@ m4_include([m4/check_random.m4]) m4_include([m4/check_steady_clock.m4]) m4_include([m4/check_tcp_info.m4]) -m4_include([m4/check_thread_local.m4]) m4_include([m4/check_time.m4]) m4_include([m4/d-type.m4]) m4_include([m4/fz_checkversion.m4]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/config/config.hpp.in new/libfilezilla-0.56.1/config/config.hpp.in --- old/libfilezilla-0.56.0/config/config.hpp.in 2026-05-28 11:09:25.000000000 +0200 +++ new/libfilezilla-0.56.1/config/config.hpp.in 2026-06-04 11:06:29.000000000 +0200 @@ -40,27 +40,12 @@ /* getrandom can be used */ #undef HAVE_GETRANDOM -/* Define to 1 if you have the 'gmtime_r' function. */ -#undef HAVE_GMTIME_R - -/* gmtime_s can be used */ -#undef HAVE_GMTIME_S - /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the 'localtime_r' function. */ -#undef HAVE_LOCALTIME_R - -/* localtime_s can be used */ -#undef HAVE_LOCALTIME_S - /* Define if MEMFD_CREATE is supported */ #undef HAVE_MEMFD_CREATE -/* Define if thread_local isn't supported */ -#undef HAVE_NO_THREAD_LOCAL - /* Define to 1 if you have the 'pipe2' function. */ #undef HAVE_PIPE2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/configure new/libfilezilla-0.56.1/configure --- old/libfilezilla-0.56.0/configure 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/configure 2026-06-04 11:06:26.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for libfilezilla 0.56.0. +# Generated by GNU Autoconf 2.72 for libfilezilla 0.56.1. # # Report bugs to <[email protected]>. # @@ -614,8 +614,8 @@ # Identity of this package. PACKAGE_NAME='libfilezilla' PACKAGE_TARNAME='libfilezilla' -PACKAGE_VERSION='0.56.0' -PACKAGE_STRING='libfilezilla 0.56.0' +PACKAGE_VERSION='0.56.1' +PACKAGE_STRING='libfilezilla 0.56.1' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='https://lib.filezilla-project.org/' @@ -1477,7 +1477,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures libfilezilla 0.56.0 to adapt to many kinds of systems. +'configure' configures libfilezilla 0.56.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1548,7 +1548,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libfilezilla 0.56.0:";; + short | recursive ) echo "Configuration of libfilezilla 0.56.1:";; esac cat <<\_ACEOF @@ -1705,7 +1705,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libfilezilla configure 0.56.0 +libfilezilla configure 0.56.1 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2110,7 +2110,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libfilezilla $as_me 0.56.0, which was +It was created by libfilezilla $as_me 0.56.1, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3106,7 +3106,7 @@ # If any interfaces have been added since the last public release, then increment age. # If any interfaces have been removed or changed since the last public release, then set age to 0. # CURRENT:REVISION:AGE -LIBRARY_VERSION=58:0:0 +LIBRARY_VERSION=58:1:0 @@ -3814,7 +3814,7 @@ # Define the identity of the package. PACKAGE='libfilezilla' - VERSION='0.56.0' + VERSION='0.56.1' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -20533,63 +20533,6 @@ -# No thread_local in GCC 4.7 and it for some reason isn't supported on OS X either - - - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for thread_local" >&5 -printf %s "checking for thread_local... " >&6; } - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - -int -main (void) -{ - - thread_local static int foo = 0; - (void)foo; - return 0; - - ; - return 0; -} - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -else case e in #( - e) - -printf "%s\n" "#define HAVE_NO_THREAD_LOCAL 1" >>confdefs.h - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} @@ -20805,122 +20748,6 @@ - - for ac_func in localtime_r -do : - ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" -if test "x$ac_cv_func_localtime_r" = xyes -then : - printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h - -else case e in #( - e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for localtime_s" >&5 -printf %s "checking for localtime_s... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - #include <time.h> - -int -main (void) -{ - - time_t t; - struct tm m; - localtime_s(&m, &t); - return 0; - - ; - return 0; -} - -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_LOCALTIME_S 1" >>confdefs.h - - -else case e in #( - e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - as_fn_error $? "No threadsafe variant of localtime found" "$LINENO" 5 - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi - -done - - - - for ac_func in gmtime_r -do : - ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r" -if test "x$ac_cv_func_gmtime_r" = xyes -then : - printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h - -else case e in #( - e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gmtime_s" >&5 -printf %s "checking for gmtime_s... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - #include <time.h> - -int -main (void) -{ - - time_t t; - struct tm m; - gmtime_s(&m, &t); - return 0; - - ; - return 0; -} - -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_GMTIME_S 1" >>confdefs.h - - -else case e in #( - e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - as_fn_error $? "No threadsafe variant of gmtime found" "$LINENO" 5 - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi - -done - - # We need an inverse for gmtime, either timegm or _mkgmtime for ac_func in timegm @@ -25915,7 +25742,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libfilezilla $as_me 0.56.0, which was +This file was extended by libfilezilla $as_me 0.56.1, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -25984,7 +25811,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -libfilezilla config.status 0.56.0 +libfilezilla config.status 0.56.1 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/configure.ac new/libfilezilla-0.56.1/configure.ac --- old/libfilezilla-0.56.0/configure.ac 2026-05-28 11:09:15.000000000 +0200 +++ new/libfilezilla-0.56.1/configure.ac 2026-06-04 11:06:23.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([libfilezilla],[0.56.0],[[email protected]],[],[https://lib.filezilla-project.org/]) +AC_INIT([libfilezilla],[0.56.1],[[email protected]],[],[https://lib.filezilla-project.org/]) # Update the version information only immediately before a public release of your software # If the library source code has changed at all since the last update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’). @@ -6,7 +6,7 @@ # If any interfaces have been added since the last public release, then increment age. # If any interfaces have been removed or changed since the last public release, then set age to 0. # CURRENT:REVISION:AGE -LIBRARY_VERSION=58:0:0 +LIBRARY_VERSION=58:1:0 AH_TOP([ #ifndef LIBFILEZILLA_CONFIG_HEADER @@ -101,9 +101,6 @@ # libstdc++ as shipped with GCC 4.7 has a steady clock that isn't steady (who implements such crap?) CHECK_STEADY_CLOCK -# No thread_local in GCC 4.7 and it for some reason isn't supported on OS X either -CHECK_THREAD_LOCAL - AC_CHECK_DECLS([CLOCK_MONOTONIC], [], [], [[#include <time.h>]]) if test "$windows" = "0"; then @@ -119,8 +116,6 @@ # Some platforms have no d_type entry in their dirent structure gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE -CHECK_THREADSAFE_LOCALTIME -CHECK_THREADSAFE_GMTIME CHECK_INVERSE_GMTIME CHECK_CLOCK_GETTIME diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/demos/Makefile.in new/libfilezilla-0.56.1/demos/Makefile.in --- old/libfilezilla-0.56.0/demos/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/demos/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -115,7 +115,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/doc/Makefile.in new/libfilezilla-0.56.1/doc/Makefile.in --- old/libfilezilla-0.56.0/doc/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/doc/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -109,7 +109,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/lib/Makefile.in new/libfilezilla-0.56.1/lib/Makefile.in --- old/libfilezilla-0.56.0/lib/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/lib/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -134,7 +134,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/lib/file.cpp new/libfilezilla-0.56.1/lib/file.cpp --- old/libfilezilla-0.56.0/lib/file.cpp 2026-02-10 09:52:49.000000000 +0100 +++ new/libfilezilla-0.56.1/lib/file.cpp 2026-06-03 17:15:55.000000000 +0200 @@ -32,6 +32,26 @@ close(); } +namespace { +bool check_flags(file::creation_flags & d) +{ + if (d & file::existing) { + if (d & file::empty) { + return false; + } + } + else if (!(d & file::empty)) { + d |= (d & file::fresh) ? file::empty : file::existing; + } + + if (d & file::fresh && d & file::nocreate) { + return false; + } + + return true; +} +} + #ifdef FZ_WINDOWS file::file(file && op) noexcept : fd_{op.fd_} @@ -74,14 +94,19 @@ return {result::invalid}; } + DWORD dispositionFlags; if (m == writing || m == readwrite || m == appending) { - if (d & empty) { - dispositionFlags = (d & nocreate) ? TRUNCATE_EXISTING : CREATE_ALWAYS; + if (!check_flags(d)) { + return {result::invalid}; } - else if (d & fresh) { + + if (d & fresh) { dispositionFlags = CREATE_NEW; } + else if (d & empty) { + dispositionFlags = (d & nocreate) ? TRUNCATE_EXISTING : CREATE_ALWAYS; + } else if (d & nocreate) { dispositionFlags = OPEN_EXISTING; } @@ -305,11 +330,16 @@ return {result::invalid}; } + int flags = O_CLOEXEC; if (m == reading) { flags |= O_RDONLY; } else { + if (!check_flags(d)) { + return {result::invalid}; + } + flags |= (m == readwrite) ? O_RDWR : O_WRONLY; if (m == appending) { flags |= O_APPEND; @@ -319,12 +349,12 @@ flags |= O_CREAT; } - if (d & empty) { - flags |= O_TRUNC; - } - else if (d & fresh) { + if (d & fresh) { flags |= O_EXCL; } + else if (d & empty) { + flags |= O_TRUNC; + } } int mode = S_IRUSR | S_IWUSR; if (!(d & (current_user_only | current_user_and_admins_only))) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/lib/libfilezilla/time.hpp new/libfilezilla-0.56.1/lib/libfilezilla/time.hpp --- old/libfilezilla-0.56.0/lib/libfilezilla/time.hpp 2025-07-16 11:21:37.000000000 +0200 +++ new/libfilezilla-0.56.1/lib/libfilezilla/time.hpp 2026-06-04 11:06:23.000000000 +0200 @@ -134,6 +134,7 @@ * * Adding or subtracting a \ref duration interval is accuracy-aware, e.g. adding a single second to a datetime with * minute-accuracy does not change the timestamp. + * \{ */ datetime& operator+=(duration const& op); datetime operator+(duration const& op) const { datetime t(*this); t += op; return t; } @@ -207,7 +208,13 @@ static bool verify_format(std::wstring const& fmt); /// Get millisecond part of timestamp - int get_milliseconds() const { return t_ % 1000; } + int get_milliseconds() const { + int ms = static_cast<int>(t_ % 1000); + if (ms < 0) { + ms += 1000; + } + return ms; + } /// Get timestamp as time_t, seconds since 1970-01-01 00:00:00 time_t get_time_t() const; @@ -215,7 +222,7 @@ /** \brief Get timestamp as struct tm * * Undefined if datetime is empty. - * + * * Note: On Windows the tm_yday and tm_isdst fields are undefined. */ tm get_tm(zone z) const; @@ -284,7 +291,7 @@ * have the time unit as part of the function name. * * In contract to \ref datetime, \c duration does not track accuracy. - * + * * \note Arithmetic operations on duration do not check for integer over/underflow */ class FZ_PUBLIC_SYMBOL duration final @@ -303,6 +310,9 @@ int64_t get_milliseconds() const { return ms_; } /// \} + /** \name Setters + * \{ + */ static duration from_days(int64_t m) { return duration(m * 1000 * 60 * 60 * 24); } @@ -320,6 +330,7 @@ } /// \} + /// \{ duration& operator+=(duration const& op) { ms_ += op.ms_; return *this; @@ -347,6 +358,7 @@ ms_ *= op; return *this; } + /// \} duration absolute() const { return (ms_ < 0) ? duration(-ms_) : *this; @@ -382,7 +394,6 @@ } /** \relates datetime - * \relatesalso duration * \brief Gets the difference between two timestamps as \ref duration * * This function ignores accuracy, it treats both timestamps as if they had millisecond-accuracy. @@ -419,7 +430,7 @@ } monotonic_clock const operator-(duration const& d) const { - return monotonic_clock(*this) += d; + return monotonic_clock(*this) -= d; } private: @@ -464,7 +475,6 @@ }; /** \relates monotonic_clock - * \relatesalso duration * Gets the difference between two clocks as \ref duration */ inline duration operator-(monotonic_clock const& a, monotonic_clock const& b) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/lib/socket.cpp new/libfilezilla-0.56.1/lib/socket.cpp --- old/libfilezilla-0.56.0/lib/socket.cpp 2026-05-28 11:09:15.000000000 +0200 +++ new/libfilezilla-0.56.1/lib/socket.cpp 2026-06-03 17:15:55.000000000 +0200 @@ -525,7 +525,7 @@ return fd; } - int try_connect_host(addrinfo & addr, sockaddr_u const& bindAddr, scoped_lock & l) + int try_connect_host(addrinfo & addr, sockaddr_u const& bindAddr, socklen_t bindAddrLen, scoped_lock & l) { if (socket_->evt_handler_) { socket_->evt_handler_->send_event<hostaddress_event>(socket_->ev_source_, socket::address_to_string(addr.ai_addr, addr.ai_addrlen)); @@ -542,7 +542,7 @@ if (bindAddr.sockaddr_.sa_family != AF_UNSPEC) { if (bindAddr.sockaddr_.sa_family == addr.ai_family) { - if (bind(socket_->fd_, &bindAddr.sockaddr_, sizeof(bindAddr)) != 0) { + if (bind(socket_->fd_, &bindAddr.sockaddr_, bindAddrLen) != 0) { if (socket_->evt_handler_) { socket_->evt_handler_->send_event<socket_event>(socket_->ev_source_, addr.ai_next ? socket_event_flag::connection_next : socket_event_flag::connection, last_socket_error()); } @@ -647,6 +647,7 @@ std::swap(bind, bind_); sockaddr_u bindAddr{}; + socklen_t bindAddrLen{}; #ifndef FZ_WINDOWS @@ -668,7 +669,7 @@ addr.ai_addr = &u.sockaddr_; addr.ai_addrlen = sizeof(u.un); - int res = try_connect_host(addr, bindAddr, l); + int res = try_connect_host(addr, bindAddr, bindAddrLen, l); if (res == 1) { return true; } @@ -691,6 +692,7 @@ if (!res && bindAddressList) { if (bindAddressList->ai_addr) { memcpy(&bindAddr.storage, bindAddressList->ai_addr, bindAddressList->ai_addrlen); + bindAddrLen = bindAddressList->ai_addrlen; } freeaddrinfo(bindAddressList); } @@ -757,7 +759,7 @@ res = 0; for (addrinfo *addr = addressList; addr && !res; addr = addr->ai_next) { - res = try_connect_host(*addr, bindAddr, l); + res = try_connect_host(*addr, bindAddr, bindAddrLen, l); } freeaddrinfo(addressList); if (res == 1) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/lib/time.cpp new/libfilezilla-0.56.1/lib/time.cpp --- old/libfilezilla-0.56.0/lib/time.cpp 2022-09-05 15:38:03.000000000 +0200 +++ new/libfilezilla-0.56.1/lib/time.cpp 2026-06-04 11:06:23.000000000 +0200 @@ -100,6 +100,7 @@ return dt.set(st, a, z); #else tm t{}; + t.tm_isdst = -1; if (!parse(it, end, 4, t.tm_year, -1900) || !parse(it, end, 2, t.tm_mon, -1) || !parse(it, end, 2, t.tm_mday, 0)) @@ -700,7 +701,11 @@ time_t datetime::get_time_t() const { - return t_ / 1000; + int64_t seconds = t_ / 1000; + if (t_ % 1000 < 0) { + --seconds; + } + return seconds; } tm datetime::get_tm(zone z) const @@ -708,7 +713,7 @@ tm ret{}; #ifdef FZ_WINDOWS // gmtime_s/localtime_s don't work with negative times - auto constexpr y2k38_limit = ((int64_t(2) << 31) - 86400) * 1000; + auto constexpr y2k38_limit = ((int64_t(1) << 31) - 86400) * 1000; if (t_ < 86400000 || (sizeof(time_t) == 4 && t_ >= y2k38_limit)) { FILETIME ft = get_filetime(); SYSTEMTIME st; @@ -852,7 +857,7 @@ if (set && tokens.size() >= 8) { int minutes{}; if (tokens[7].size() == 5 && tokens[7][0] == '+') { - minutes = -fz::to_integral<int>(tokens[7].substr(1, 2), -10000) * 60 + fz::to_integral<int>(tokens[7].substr(3), -10000); + minutes = -fz::to_integral<int>(tokens[7].substr(1, 2), -10000) * 60 - fz::to_integral<int>(tokens[7].substr(3), -10000); } else if (tokens[7].size() == 4) { minutes = fz::to_integral<int>(tokens[7].substr(0, 2), 10000) * 60 + fz::to_integral<int>(tokens[7].substr(2), 10000); @@ -941,20 +946,27 @@ set = dt.set(fz::datetime::utc, year, month, day, hour, minute, second); } - if (set && offset_pos != String::npos && str[offset_pos] != 'Z') { - auto const offset_tokens = fz::strtok_view(str.substr(offset_pos + 1), ':'); - if (offset_tokens.size() != 2) { + if (set && offset_pos != String::npos && (str[offset_pos] == '+' || str[offset_pos] == '-')) { + auto const ofs = str.substr(offset_pos + 1); + + auto isnum = [](char c) { return c >= '0' && c <= '9'; }; + if (ofs.size() != 5 || ofs[2] != ':' || !isnum(ofs[0]) || !isnum(ofs[1]) || !isnum(ofs[3]) || !isnum(ofs[4])) { dt.clear(); return false; } - int minutes = fz::to_integral<int>(offset_tokens[0], 10009) * 60 + fz::to_integral<int>(offset_tokens[1], 10000); - if (minutes < 10000) { - if (str[offset_pos] == '+') { - minutes = -minutes; - } - dt += fz::duration::from_minutes(minutes); + int hours = (ofs[0] - '0') * 10 + ofs[1] - '0'; + int minutes = (ofs[3] - '0') * 10 + ofs[4] - '0'; + if (hours > 23 || minutes > 59) { + dt.clear(); + return false; + } + + auto offset = hours * 60 + minutes; + if (str[offset_pos] == '+') { + offset = -offset; } + dt += fz::duration::from_minutes(offset); } return set; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/locales/Makefile.in new/libfilezilla-0.56.1/locales/Makefile.in --- old/libfilezilla-0.56.0/locales/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/locales/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -109,7 +109,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/m4/check_thread_local.m4 new/libfilezilla-0.56.1/m4/check_thread_local.m4 --- old/libfilezilla-0.56.0/m4/check_thread_local.m4 2020-07-07 14:06:31.000000000 +0200 +++ new/libfilezilla-0.56.1/m4/check_thread_local.m4 1970-01-01 01:00:00.000000000 +0100 @@ -1,24 +0,0 @@ -dnl Checks for thread_local support - -AC_DEFUN([CHECK_THREAD_LOCAL], [ - - AC_LANG_PUSH(C++) - - AC_MSG_CHECKING([for thread_local]) - - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([[ - ]], [[ - thread_local static int foo = 0; - (void)foo; - return 0; - ]]) - ], [ - AC_MSG_RESULT([yes]) - ], [ - AC_DEFINE([HAVE_NO_THREAD_LOCAL], [1], [Define if thread_local isn't supported]) - AC_MSG_RESULT([no]) - ]) - - AC_LANG_POP(C++) -]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/m4/check_time.m4 new/libfilezilla-0.56.1/m4/check_time.m4 --- old/libfilezilla-0.56.0/m4/check_time.m4 2024-06-26 11:40:18.000000000 +0200 +++ new/libfilezilla-0.56.1/m4/check_time.m4 2026-06-03 17:15:55.000000000 +0200 @@ -1,52 +1,3 @@ -dnl We need the threadsafe variants of localtime -AC_DEFUN([CHECK_THREADSAFE_LOCALTIME], -[ - AC_CHECK_FUNCS(localtime_r, [], [ - AC_MSG_CHECKING([for localtime_s]) - dnl Checking for localtime_s is a bit more complex as it is a macro - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[ - #include <time.h> - ]], [[ - time_t t; - struct tm m; - localtime_s(&m, &t); - return 0; - ]]) - ], [ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_LOCALTIME_S], [1], [localtime_s can be used]) - ], [ - AC_MSG_RESULT([no]) - AC_MSG_ERROR([No threadsafe variant of localtime found]) - ]) - ]) -]) - -dnl We need the threadsafe variants of gmtime -AC_DEFUN([CHECK_THREADSAFE_GMTIME], [ - AC_CHECK_FUNCS(gmtime_r, [], [ - AC_MSG_CHECKING([for gmtime_s]) - dnl Checking for gmtime_s is a bit more complex as it is a macro - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[ - #include <time.h> - ]], [[ - time_t t; - struct tm m; - gmtime_s(&m, &t); - return 0; - ]]) - ], [ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_GMTIME_S], [1], [gmtime_s can be used]) - ], [ - AC_MSG_RESULT([no]) - AC_MSG_ERROR([No threadsafe variant of gmtime found]) - ]) - ]) -]) - dnl We need an inverse for gmtime, either timegm or _mkgmtime AC_DEFUN([CHECK_INVERSE_GMTIME], [ # We need an inverse for gmtime, either timegm or _mkgmtime diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/tests/Makefile.in new/libfilezilla-0.56.1/tests/Makefile.in --- old/libfilezilla-0.56.0/tests/Makefile.in 2026-05-28 11:09:22.000000000 +0200 +++ new/libfilezilla-0.56.1/tests/Makefile.in 2026-06-04 11:06:26.000000000 +0200 @@ -113,7 +113,6 @@ $(top_srcdir)/m4/check_random.m4 \ $(top_srcdir)/m4/check_steady_clock.m4 \ $(top_srcdir)/m4/check_tcp_info.m4 \ - $(top_srcdir)/m4/check_thread_local.m4 \ $(top_srcdir)/m4/check_time.m4 $(top_srcdir)/m4/d-type.m4 \ $(top_srcdir)/m4/fz_checkversion.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/tests/socket.cpp new/libfilezilla-0.56.1/tests/socket.cpp --- old/libfilezilla-0.56.0/tests/socket.cpp 2025-07-31 13:05:59.000000000 +0200 +++ new/libfilezilla-0.56.1/tests/socket.cpp 2026-06-03 17:15:55.000000000 +0200 @@ -15,6 +15,7 @@ class socket_test final : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(socket_test); + CPPUNIT_TEST(test_bound_connect); CPPUNIT_TEST(test_duplex); CPPUNIT_TEST(test_duplex_tls); CPPUNIT_TEST(test_tls_resumption); @@ -24,23 +25,21 @@ void setUp() {} void tearDown() {} + void test_bound_connect(); + void do_test_bound_connect(std::string const& address, fz::address_type family); + void test_duplex(); void test_duplex_tls(); + void test_tls_resumption(); void do_test_tls_resumption(std::optional<fz::tls_ver> ver, bool server_no_ticket, bool client_no_ticket, bool use_hostname); void do_test_tls_resumption(std::optional<fz::tls_ver> ver, bool server_no_ticket, bool client_no_ticket); - void test_tls_resumption(); + }; CPPUNIT_TEST_SUITE_REGISTRATION(socket_test); namespace { -struct logger : public fz::logger_interface -{ - virtual void do_log(fz::logmsg::type, std::wstring &&) { - } -}; - auto const& get_key_and_cert() { static auto key_and_cert = fz::tls_layer::generate_selfsigned_certificate(fz::native_string(), "CN=libfilezilla test", {}); @@ -175,8 +174,6 @@ fz::hash_accumulator sent_hash_{fz::hash_algorithm::md5}; fz::hash_accumulator received_hash_{fz::hash_algorithm::md5}; - logger logger_; - fz::mutex m_; fz::condition cond_; @@ -204,7 +201,8 @@ { s_ = std::make_unique<fz::socket>(pool_, this); if (tls) { - tls_ = std::make_unique<fz::tls_layer>(loop, this, *s_, nullptr, logger_); + auto & logger = fz::get_null_logger(); + tls_ = std::make_unique<fz::tls_layer>(loop, this, *s_, nullptr, logger); if (tls_ver_) { tls_->set_min_tls_ver(*tls_ver_); tls_->set_max_tls_ver(*tls_ver_); @@ -276,7 +274,8 @@ fail(__LINE__, error); } if (use_tls_) { - tls_ = std::make_unique<fz::tls_layer>(event_loop_, this, *s_, nullptr, logger_); + auto & logger = fz::get_null_logger(); + tls_ = std::make_unique<fz::tls_layer>(event_loop_, this, *s_, nullptr, logger); if (tls_ver_) { tls_->set_min_tls_ver(*tls_ver_); tls_->set_max_tls_ver(*tls_ver_); @@ -306,6 +305,133 @@ bool use_tls_{}; bool no_tickets_{}; }; + +struct bound_connect final : fz::event_handler +{ + explicit bound_connect(fz::event_loop & loop) + : fz::event_handler(loop) + { + } + + virtual ~bound_connect() + { + remove_handler(); + } + + bool start(std::string const& address, fz::address_type family, int& error) + { + if (!l_.bind(address)) { + error = EINVAL; + return false; + } + + error = l_.listen(family); + if (error) { + return false; + } + + int port_error{}; + port_ = l_.local_port(port_error); + if (port_ == -1) { + error = port_error; + return false; + } + + if (!s_.bind(address)) { + error = EINVAL; + return false; + } + + error = s_.connect(fz::to_native(address), port_, family); + return !error; + } + + bool wait(fz::duration const& timeout) + { + fz::scoped_lock l(m_); + while (failed_.empty() && (!accepted_ || !connected_)) { + if (!cond_.wait(l, timeout)) { + return false; + } + } + return true; + } + + virtual void operator()(fz::event_base const& ev) override + { + fz::dispatch<fz::socket_event>(ev, this, &bound_connect::on_socket_event); + } + + void on_socket_event(fz::socket_event_source * source, fz::socket_event_flag type, int error) + { + if (error) { + fail(__LINE__, error); + return; + } + + if (type != fz::socket_event_flag::connection) { + fail(__LINE__); + return; + } + + if (source == &l_) { + int accept_error{}; + auto accepted = l_.accept(accept_error); + if (!accepted) { + fail(__LINE__, accept_error); + return; + } + + fz::scoped_lock l(m_); + accepted_ = std::move(accepted); + signal_if_done(l); + } + else if (source == &s_) { + fz::scoped_lock l(m_); + connected_ = true; + signal_if_done(l); + } + else { + fail(__LINE__); + } + } + + void fail(int line, int error = 0) + { + fz::scoped_lock l(m_); + if (failed_.empty()) { + failed_ = fz::sprintf("error in line %d"sv, line); + if (error) { + failed_ += fz::sprintf(", error code %d"sv, error); + } + } + cond_.signal(l); + } + + void signal_if_done(fz::scoped_lock& l) + { + if (accepted_ && connected_) { + cond_.signal(l); + } + } + + std::string failure() const + { + fz::scoped_lock l(m_); + return failed_; + } + + fz::thread_pool pool_; + fz::listen_socket l_{pool_, this}; + fz::socket s_{pool_, this}; + + mutable fz::mutex m_; + fz::condition cond_; + std::unique_ptr<fz::socket> accepted_; + std::string failed_; + bool connected_{}; + int port_{}; +}; } void socket_test::test_duplex() @@ -342,6 +468,25 @@ CPPUNIT_ASSERT(s.sent_hash_.digest() == c.received_hash_.digest()); } +void socket_test::do_test_bound_connect(std::string const& address, fz::address_type family) +{ + fz::event_loop loop; + bound_connect c(loop); + + int error{}; + bool const started = c.start(address, family, error); + CPPUNIT_ASSERT_MESSAGE(fz::sprintf("Could not start bound connection test for %s, error code %d"sv, address, error), started); + + CPPUNIT_ASSERT_MESSAGE(fz::sprintf("Timed out waiting for bound connection test for %s"sv, address), c.wait(fz::duration::from_minutes(1))); + ASSERT_EQUAL(std::string(), c.failure()); +} + +void socket_test::test_bound_connect() +{ + do_test_bound_connect("127.0.0.1", fz::address_type::ipv4); + do_test_bound_connect("::1", fz::address_type::ipv6); +} + void socket_test::test_duplex_tls() { // Full duplex socket test of random data exchanged in both directions for 5 seconds, but this time wit TLS on top. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.56.0/tests/time.cpp new/libfilezilla-0.56.1/tests/time.cpp --- old/libfilezilla-0.56.0/tests/time.cpp 2025-07-31 13:05:59.000000000 +0200 +++ new/libfilezilla-0.56.1/tests/time.cpp 2026-06-04 11:06:23.000000000 +0200 @@ -85,6 +85,20 @@ CPPUNIT_ASSERT_EQUAL(23, tm2.tm_hour); CPPUNIT_ASSERT_EQUAL(59, tm2.tm_min); CPPUNIT_ASSERT_EQUAL(59, tm2.tm_sec); + + fz::datetime t3(fz::datetime::utc, 1960, 10, 20, 12, 34, 22, 7); + + CPPUNIT_ASSERT(!t3.empty()); + CPPUNIT_ASSERT_EQUAL(7, t3.get_milliseconds()); + + t3 = fz::datetime(t3.get_time_t(), fz::datetime::seconds); + auto const tm3 = t3.get_tm(fz::datetime::utc); + CPPUNIT_ASSERT_EQUAL(60, tm3.tm_year); + CPPUNIT_ASSERT_EQUAL(9, tm3.tm_mon); + CPPUNIT_ASSERT_EQUAL(20, tm3.tm_mday); + CPPUNIT_ASSERT_EQUAL(12, tm3.tm_hour); + CPPUNIT_ASSERT_EQUAL(34, tm3.tm_min); + CPPUNIT_ASSERT_EQUAL(22, tm3.tm_sec); } void TimeTest::testAlternateMidnight() @@ -122,11 +136,17 @@ std::string const offset1 = "Mon, 02 Mar 2020 13:35:00 +0100"; std::string const offset2 = "Mon, 02 Mar 2020 07:35:00 -0500"; + std::string const offset3 = "Mon, 02 Mar 2020 14:05:00 +0130"; + std::string const offset4 = "Mon, 02 Mar 2020 07:05:00 -0530"; CPPUNIT_ASSERT(t.set_rfc822(offset1)); CPPUNIT_ASSERT(t == t1); CPPUNIT_ASSERT(t.set_rfc822(offset2)); CPPUNIT_ASSERT(t == t1); + CPPUNIT_ASSERT(t.set_rfc822(offset3)); + CPPUNIT_ASSERT(t == t1); + CPPUNIT_ASSERT(t.set_rfc822(offset4)); + CPPUNIT_ASSERT(t == t1); } void TimeTest::testRFC3339()
