Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package unionfs-fuse for openSUSE:Factory 
checked in at 2026-10-18 19:26:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/unionfs-fuse (Old)
 and      /work/SRC/openSUSE:Factory/.unionfs-fuse.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "unionfs-fuse"

Sun Oct 18 19:26:46 2026 rev:24 rq:1385992 version:3.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/unionfs-fuse/unionfs-fuse.changes        
2025-12-31 10:48:39.117490183 +0100
+++ /work/SRC/openSUSE:Factory/.unionfs-fuse.new.3698736/unionfs-fuse.changes   
2026-10-18 19:27:21.771898014 +0200
@@ -1,0 +2,12 @@
+Sun Oct 18 05:33:56 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 3.8:
+  * fix data corruption when copying files larger than 8 MiB
+    concurrently in cow mode
+  * fix "bad address" error when setting a debug file with
+    unionfsctl -p
+  * fix creating unix sockets on macos
+  * mount.unionfs helper no longer requires bash and accepts
+    multiple -o options
+
+-------------------------------------------------------------------

Old:
----
  v3.7.tar.gz

New:
----
  v3.8.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ unionfs-fuse.spec ++++++
--- /var/tmp/diff_new_pack.wLp23q/_old  2026-10-18 19:27:22.574931659 +0200
+++ /var/tmp/diff_new_pack.wLp23q/_new  2026-10-18 19:27:22.575931701 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package unionfs-fuse
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 # Copyright (c) 2025 Andreas Stieger <[email protected]>
 #
 # All modifications and additions to the file contributed by third parties
@@ -18,7 +18,7 @@
 
 
 Name:           unionfs-fuse
-Version:        3.7
+Version:        3.8
 Release:        0
 Summary:        Userspace Unionfs File System
 License:        BSD-3-Clause
@@ -28,12 +28,8 @@
 BuildRequires:  cmake
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(fuse3)
-Requires:       fuse3
-%if 0%{?suse_version} >= 1600
 BuildRequires:  pkgconfig(libattr)
-%else
-BuildRequires:  libattr-devel
-%endif
+Requires:       fuse3
 
 %description
 unionfs-fuse overlays several directory into one single mount point

++++++ v3.7.tar.gz -> v3.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/.github/workflows/cmake.yml 
new/unionfs-fuse-3.8/.github/workflows/cmake.yml
--- old/unionfs-fuse-3.7/.github/workflows/cmake.yml    2025-09-14 
19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/.github/workflows/cmake.yml    2026-10-10 
20:53:12.000000000 +0200
@@ -30,9 +30,9 @@
             clang_major_version: 18
             runs-on: ubuntu-24.04
           # macFUSE on macOS
-          - cc: gcc-12
+          - cc: gcc-14
             clang_major_version: null
-            runs-on: macos-13
+            runs-on: macos-14
           - cc: clang-15
             clang_major_version: 15
             runs-on: macos-14
@@ -60,7 +60,7 @@
           brew install --cask macfuse
 
       - name: Checkout Git branch
-        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # 
v5.0.0
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # 
v7.0.1
 
       - name: 'Configure with CMake'
         run: |-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/.github/workflows/makefile.yml 
new/unionfs-fuse-3.8/.github/workflows/makefile.yml
--- old/unionfs-fuse-3.7/.github/workflows/makefile.yml 2025-09-14 
19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/.github/workflows/makefile.yml 2026-10-10 
20:53:12.000000000 +0200
@@ -43,7 +43,7 @@
             python3-pytest
 
       - name: Checkout Git branch
-        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # 
v5.0.0
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # 
v7.0.1
 
       - name: 'Build and test (without coverage)'
         run: |-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/CREDITS new/unionfs-fuse-3.8/CREDITS
--- old/unionfs-fuse-3.7/CREDITS        2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/CREDITS        2026-10-10 20:53:12.000000000 +0200
@@ -41,6 +41,7 @@
 xabrouck (github)
 Timothy C. Quinn <[email protected]>
 Benjy Wiener <[email protected]>
+Samuel Duann <[email protected]>
 
 Hashtable routines taken from:
 Christopher Clark <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/LICENSE new/unionfs-fuse-3.8/LICENSE
--- old/unionfs-fuse-3.7/LICENSE        2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/LICENSE        2026-10-10 20:53:12.000000000 +0200
@@ -1,6 +1,6 @@
 Unionfs-fuse is provided under the terms of the new BSD license.
 
-Copyright (c) 2025, Radek Podgorny, Bernd Schubert
+Copyright (c) 2026, Radek Podgorny, Bernd Schubert
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/NEWS new/unionfs-fuse-3.8/NEWS
--- old/unionfs-fuse-3.7/NEWS   2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/NEWS   2026-10-10 20:53:12.000000000 +0200
@@ -1,3 +1,9 @@
+3.8
+- fix data corruption when copying files larger than 8 MiB concurrently in cow 
mode
+- fix "bad address" error when setting a debug file with unionfsctl -p
+- fix creating unix sockets on macos
+- mount.unionfs helper no longer requires bash and accepts multiple -o options
+
 3.7
 - fix chmod on symlink itself
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/man/unionfs.8 
new/unionfs-fuse-3.8/man/unionfs.8
--- old/unionfs-fuse-3.7/man/unionfs.8  2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/man/unionfs.8  2026-10-10 20:53:12.000000000 +0200
@@ -7,7 +7,7 @@
 .ft R
 .fi
 ..
-.TH "unionfs" "8" "2025" "unionfs-fuse 3.7" ""
+.TH "unionfs" "8" "2026" "unionfs-fuse 3.8" ""
 .SH "NAME"
 unionfs\-fuse \- A userspace unionfs implementation
 .SH "SYNOPSIS"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/mount.unionfs 
new/unionfs-fuse-3.8/mount.unionfs
--- old/unionfs-fuse-3.7/mount.unionfs  2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/mount.unionfs  2026-10-10 20:53:12.000000000 +0200
@@ -1,9 +1,27 @@
-#!/bin/bash
-
-label=$1
-mpoint=$2
-shift 3
-dirs=${@##*,dirs=}
-dirs=${dirs/,/:}
-mount.fuse "unionfs#$dirs" "$mpoint" -o ${@%%,dirs=*} 
-
+#!/bin/sh
+set -f
+print_usage() { echo "usage: ${0##*/} <ignored> destination" \
+    "-o dirs=UNION_DIRS[,opt[,opts...]]"; }
+first_arg=y first_pos=y is_opt='' dirs=''
+IFS=; for arg in "$@"; do
+    [ -z "$first_arg" ] || { first_arg=; set --; }
+    if [ -n "$is_opt" ]; then
+        is_opt='' new_arg=''
+        IFS=,; for part in $arg; do
+            case "$part" in
+                dirs=*) dirs="${dirs:+$dirs:}${part#dirs=}" ;;
+                *) new_arg="${new_arg:+$new_arg,}$part" ;;
+            esac
+        done
+        [ -n "$new_arg" ] || continue
+        set -- "$@" -o "$new_arg"
+    elif [ "-o" = "$arg" ]; then
+        is_opt=y
+    elif [ -n "$first_pos" ] && [ "${arg#-}" = "$arg" ]; then
+        first_pos=''
+    else
+        set -- "$@" "$arg"
+    fi
+done
+[ -n "$dirs" ] && [ -z "$is_opt" ] || { print_usage >&2; exit 1; }
+exec mount.fuse "unionfs#$dirs" "$@"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/src/cow_utils.c 
new/unionfs-fuse-3.8/src/cow_utils.c
--- old/unionfs-fuse-3.7/src/cow_utils.c        2025-09-14 19:29:51.000000000 
+0200
+++ new/unionfs-fuse-3.8/src/cow_utils.c        2026-10-10 20:53:12.000000000 
+0200
@@ -149,7 +149,6 @@
 {
        DBG("from %s to %s\n", cow->from_path, cow->to_path);
 
-       static char buf[MAXBSIZE];
        struct stat to_stat, *fs;
        int from_fd, rcount, to_fd, wcount;
        int rval = 0;
@@ -199,6 +198,14 @@
        } else
 #endif
        {
+               char *buf = malloc(MAXBSIZE);
+               if (!buf) {
+                       USYSLOG(LOG_WARNING, "malloc failed: %s", 
cow->from_path);
+                       (void)close(from_fd);
+                       (void)close(to_fd);
+                       RETURN(1);
+               }
+
                while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
                        wcount = write(to_fd, buf, rcount);
                        if (rcount != wcount || wcount == -1) {
@@ -211,6 +218,8 @@
                        USYSLOG(LOG_WARNING, "copy failed: %s", cow->from_path);
                        rval = 1;
                }
+
+               free(buf);
        }
 
        if (rval == 1) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/src/fuse_ops.c 
new/unionfs-fuse-3.8/src/fuse_ops.c
--- old/unionfs-fuse-3.7/src/fuse_ops.c 2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/src/fuse_ops.c 2026-10-10 20:53:12.000000000 +0200
@@ -39,6 +39,11 @@
        #include <sys/statvfs.h>
 #endif
 
+#ifdef __APPLE__
+       #include <sys/socket.h>
+       #include <sys/un.h>
+#endif
+
 #ifdef HAVE_XATTR
        #include <sys/xattr.h>
 #endif
@@ -391,6 +396,22 @@
 
                res = creat(p, 0);
                if (res > 0 && close(res) == -1) USYSLOG(LOG_WARNING, "Warning, 
cannot close file\n");
+#ifdef __APPLE__
+       } else if ((file_type) == S_IFSOCK) {
+        int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+
+        if (sockfd >= 0) {
+                       // Bind (and immediately close) the socket in order to 
create the file on
+                       // the underlying filesystem
+                       struct sockaddr_un sock_addr;
+            sock_addr.sun_family = AF_UNIX;
+            strncpy(sock_addr.sun_path, p, sizeof(sock_addr.sun_path));
+            res = bind(sockfd, (struct sockaddr*)&sock_addr, 
sizeof(sock_addr));
+            close(sockfd);
+        } else {
+            res = -1;
+        }
+#endif
        } else {
                res = mknod(p, file_type, rdev);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/src/unionfsctl.c 
new/unionfs-fuse-3.8/src/unionfsctl.c
--- old/unionfs-fuse-3.7/src/unionfsctl.c       2025-09-14 19:29:51.000000000 
+0200
+++ new/unionfs-fuse-3.8/src/unionfsctl.c       2026-10-10 20:53:12.000000000 
+0200
@@ -44,25 +44,27 @@
 
        int opt;
        const char* argument_param;
+       char debug_file[PATHLEN_MAX] = {0};
        int debug_on_off;
        int ioctl_res;
        while ((opt = getopt(argc, argv, "d:p:")) != -1) {
                switch (opt) {
                case 'p':
-                       argument_param = optarg;
-                       if (strlen(argument_param) < 1) {
+                       if (strlen(optarg) < 1) {
                                fprintf(stderr,
                                        "Not a valid debug path given!\n");
                                print_help(progname);
                                exit(1);
                        }
 
-                       if (strlen(argument_param) > PATHLEN_MAX) {
+                       if (strlen(optarg) > PATHLEN_MAX) {
                                fprintf(stderr, "Debug path too long!\n");
                                exit(1);
                        }
 
-                       ioctl_res = ioctl(fd, UNIONFS_SET_DEBUG_FILE, 
argument_param);
+                       strncpy(debug_file, optarg, PATHLEN_MAX - 1);
+
+                       ioctl_res = ioctl(fd, UNIONFS_SET_DEBUG_FILE, 
debug_file);
                        if (ioctl_res == -1) {
                                fprintf(stderr, "debug-file ioctl failed: %s\n",
                                        strerror(errno) );
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/src/version.h 
new/unionfs-fuse-3.8/src/version.h
--- old/unionfs-fuse-3.7/src/version.h  2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/src/version.h  2026-10-10 20:53:12.000000000 +0200
@@ -4,5 +4,5 @@
 */
 
 #ifndef _VERSION_H
-#define VERSION "3.7"
+#define VERSION "3.8"
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/unionfs-fuse-3.7/test_all.py 
new/unionfs-fuse-3.8/test_all.py
--- old/unionfs-fuse-3.7/test_all.py    2025-09-14 19:29:51.000000000 +0200
+++ new/unionfs-fuse-3.8/test_all.py    2026-10-10 20:53:12.000000000 +0200
@@ -13,6 +13,7 @@
 import stat
 import platform
 import errno
+import threading
 
 
 def call(cmd):
@@ -264,6 +265,57 @@
                self.assertFalse(os.path.isfile('rw1/ro_file'))
                self.assertEqual(read_from_file('ro1/ro1_file'), 'ro1')
 
+       def test_concurrent_cow(self):
+               # copy_file() used to share a static buffer between threads. 
Files of
+               # up to 8 MiB are copied via mmap and never touch that buffer, 
so the
+               # files have to be bigger than that to exercise the read/write 
loop.
+               num_threads = 4
+               file_size = 9 * 1024 * 1024
+               files = []
+
+               for idx in range(num_threads):
+                       fn = 'ro1/concurrent_cow_%d' % idx
+                       pattern = (chr(ord('A') + idx) * 1024).encode('ascii') 
* (file_size // 1024)
+                       with open(fn, 'wb') as f:
+                               f.write(pattern)
+                       files.append(('concurrent_cow_%d' % idx, pattern))
+
+               barrier = threading.Barrier(num_threads)
+               errors = []
+
+               def worker(fname, pat):
+                       try:
+                               barrier.wait()
+                               # Open with read+write to trigger COW copy of 
original file from ro1 to rw1
+                               with open('union/%s' % fname, 'r+b') as f:
+                                       data = f.read()
+                                       if data != pat:
+                                               errors.append("Initial read 
mismatch for %s: got len %d, expected %d" % (fname, len(data), len(pat)))
+                                       f.seek(0)
+                                       f.write(b'MODIFIED_' + pat[9:])
+                       except Exception as e:
+                               errors.append("Exception in worker for %s: %s" 
% (fname, e))
+
+               threads = [
+                       threading.Thread(target=worker, args=(fn, pat))
+                       for fn, pat in files
+               ]
+               for t in threads:
+                       t.start()
+               for t in threads:
+                       t.join()
+
+               self.assertEqual(errors, [])
+
+               for fn, pat in files:
+                       expected = b'MODIFIED_' + pat[9:]
+                       with open('union/%s' % fn, 'rb') as f:
+                               self.assertEqual(f.read(), expected)
+                       with open('rw1/%s' % fn, 'rb') as f:
+                               self.assertEqual(f.read(), expected)
+                       with open('ro1/%s' % fn, 'rb') as f:
+                               self.assertEqual(f.read(), pat)
+
        def test_write_new(self):
                write_to_file('union/new_file', 'something')
                self.assertEqual(read_from_file('union/new_file'), 'something')

Reply via email to