Compare commits

..

No commits in common. "master" and "2.40.2" have entirely different histories.

1142 changed files with 79134 additions and 119102 deletions

527
.cirrus.yml Normal file
View file

@ -0,0 +1,527 @@
freebsd_task:
name: "freebsd:11.4"
freebsd_instance:
image_family: freebsd-11-4
env:
ASSUME_ALWAYS_YES: yes
script:
- buildtools/install-build-pkgs
- gmake -j4
freebsd_task:
name: "freebsd:12.1"
freebsd_instance:
image_family: freebsd-12-1
env:
ASSUME_ALWAYS_YES: yes
script:
- buildtools/install-build-pkgs
- gmake -j4
freebsd_task:
name: "freebsd:12.2"
freebsd_instance:
image_family: freebsd-12-2
env:
ASSUME_ALWAYS_YES: yes
script:
- buildtools/install-build-pkgs
- gmake -j4
freebsd_task:
name: "freebsd:13.0"
freebsd_instance:
image_family: freebsd-13-0
env:
ASSUME_ALWAYS_YES: yes
script:
- buildtools/install-build-pkgs
- gmake -j4
#macos_task:
# osx_instance:
# image: catalina-base
# script:
# - buildtools/install-build-pkgs
# - gmake -j4
linux_task:
name: "alpine:3.11"
container:
image: alpine:3.11
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.12"
container:
image: alpine:3.12
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.13"
container:
image: alpine:3.13
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.14"
container:
image: alpine:3.14
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.15"
container:
image: alpine:3.15
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.16"
container:
image: alpine:3.16
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:3.17"
container:
image: alpine:3.17
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine:latest"
container:
image: alpine:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "alpine-arm:latest"
arm_container:
image: alpine:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make STATIC=1 LTO=1
linux_task:
name: "centos:7"
container:
image: centos:7
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "rocky:8"
container:
image: rocky:8
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:30"
container:
image: fedora:30
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:31"
container:
image: fedora:31
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:32"
container:
image: fedora:32
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:33"
container:
image: fedora:33
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:34"
container:
image: fedora:34
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:35"
container:
image: fedora:35
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:36"
container:
image: fedora:36
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:37"
container:
image: fedora:37
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:38"
container:
image: fedora:38
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora:latest"
container:
image: fedora:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "fedora-arm:latest"
arm_container:
image: fedora:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- make
- make rpm
linux_task:
name: "ubuntu:14.04"
container:
image: ubuntu:14.04
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu:16.04"
container:
image: ubuntu:16.04
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu:18.04"
container:
image: ubuntu:18.04
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu:20.04"
container:
image: ubuntu:20.04
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu:22.04"
container:
image: ubuntu:22.04
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu:latest"
container:
image: ubuntu:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "ubuntu-arm:latest"
arm_container:
image: ubuntu:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:7"
container:
image: debian:8
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:8"
container:
image: debian:8
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:9"
container:
image: debian:9
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:10"
container:
image: debian:10
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:11"
container:
image: debian:11
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:12"
container:
image: debian:12
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian:latest"
container:
image: debian:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true
linux_task:
name: "debian-arm:latest"
arm_container:
image: debian:latest
cpu: 4
memory: 4G
timeout_in: 15m
script:
- buildtools/install-build-pkgs
- git fetch
- make deb
- apt-get -y install fuse
- dpkg -i ../*.deb
- mergerfs -v || true

7
.github/FUNDING.yml vendored
View file

@ -1,2 +1,7 @@
# These are supported funding model platforms
github: [trapexit]
custom: ['https://github.com/trapexit/support']
patreon: trapexit
custom: ['https://paypal.me/trapexit','https://buymeacoff.ee/trapexit']
ko_fi: trapexit
open_collective: trapexit

View file

@ -7,31 +7,22 @@ assignees: ''
---
See also https://trapexit.github.io/mergerfs/latest/support
**Describe the bug**
A clear and concise description of the unexpected behavior.
**Please be sure to use latest release of mergerfs to ensure the issue
still exists. Not your distro's latest but the latest official
release. Support will NOT be provided for old versions.**
**Please be sure to use latest release of mergerfs to ensure the issue still exists. Not your distro's latest but the latest official release.**
The `master` branch is **not** to be considered production ready. Feel
free to file bug reports but do so indicating clearly that you are
testing unreleased code.
The master branch is **not** to be considered production ready. Feel free to file bug reports but do so indicating clearly that you are testing unreleased code.
**To Reproduce**
Provide steps to reproduce the behavior. List **all** steps to
reproduce. **All** settings. The version of all software involved.
Steps to reproduce the behavior. List **all** steps to reproduce. **All** settings.
Please simplify the reproduction as much as possible.
* Unless it is dependenat on multiple branches, use a single branch
* Reproduce with standard tooling if possible
(touch,truncate,rm,rmdir,ln,etc.) Having to install 3rd party
software will make debugging more difficult.
- Unless it is dependenat on multiple branches, use a single branch
- Reproduce with standard tooling if possible (touch,truncate,rm,rmdir,ln,etc.) Having to install 3rd party software will make debugging more difficult.
**Expected behavior**
@ -39,38 +30,19 @@ Please simplify the reproduction as much as possible.
A clear and concise description of the expected behavior.
**Workarounds already tested**
Please list all workarounds attempted and why they were ruled out as
options.
**System information:**
* Attach output from
[mergerfs.collect-info](https://trapexit.github.io/mergerfs/latest/tooling/#mergerfscollect-info)
tool.
* Alternatively:
* OS: `lsb_release -a`
* kernel version: `uname -a`
* mergerfs version: `mergerfs --version`
* mergerfs settings / arguments: from fstab, systemd unit, command
line, OMV plugin, etc.
* List of drives, filesystems, & sizes:
* `df -h`
* `lsblk -o NAME,FSTYPE,FSSIZE,SIZE,MOUNTPOINTS,RM,RO,ROTA`
* All information about the relevant paths and files: permissions,
ownership, etc.
* All information about the application making the requests:
version, uid/gid
* Is mergerfs running within a container or used with container
technologies?
* Are the client apps using mergerfs running in a container?
* A strace of the application having a problem:
* `strace -fvTtt -s 256 -o /tmp/app.strace.txt <cmd>`
* `strace -fvTtt -s 256 -o /tmp/app.strace.txt -p <appPID>`
* strace of mergerfs while app tried to do it's thing:
* `strace -fvTtt -s 256 -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
- OS, kernel version: `uname -a`
- mergerfs version: `mergerfs -V`
- mergerfs settings
- List of drives, filesystems, & sizes:
- `df -h`
- `lsblk -f`
- A strace of the application having a problem:
- `strace -fvTtt -s 256 -o /tmp/app.strace.txt <cmd>`
- `strace -fvTtt -s 256 -o /tmp/app.strace.txt -p <appPID>`
- strace of mergerfs while app tried to do it's thing:
- `strace -fvTtt -s 256 -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
**Additional context**

42
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,42 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "7 3 * * 6"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ python, cpp ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
if: ${{ matrix.language == 'python' || matrix.language == 'cpp' }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

10
.gitignore vendored
View file

@ -14,20 +14,12 @@
# build artifacts
mergerfs
build/
obj/
src/version.hpp
VERSION
# Debian files
debian/files
debian/changelog
debian/debhelper-build-stamp
debian/mergerfs.debhelper.log
debian/mergerfs.substvars
# RPM files
rpmbuild/
# mkdocs files
mkdocs/venv
__pycache__/

View file

@ -3,15 +3,9 @@
### included in repo
* libfuse: https://github.com/libfuse/libfuse (heavily modified fork of v2.x)
* rapidhash: https://github.com/Nicoshev/rapidhash
* wyhash: https://github.com/wangyi-fudan/wyhash
* ghc::filesystem: https://github.com/gulrak/filesystem
* nonstd::optional: https://github.com/martinmoene/optional-lite
* fmt: https://github.com/fmtlib/fmt
* concurrentqueue: https://github.com/cameron314/concurrentqueue
* scope_guard: https://github.com/Neargye/scope_guard
* subprocess: https://github.com/arun11299/cpp-subprocess
* CLI11: https://github.com/CLIUtils/CLI11
* string-lite: https://github.com/martinmoene/string-lite
* boost
* download boost
* ./bootstrap.sh
* ./b2 tools/bcp
* ./dist/bin/bcp unordered/concurrent_flat_map.hpp <target_dir>

View file

@ -1,7 +1,7 @@
/*
ISC License
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2024, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

389
Makefile
View file

@ -1,4 +1,4 @@
# Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link>
# Copyright (c) 2024, Antonio SJ Musumeci <trapexit@spawn.link>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@ -12,279 +12,197 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
$(info mergerfs MAKEFLAGS: $(MAKEFLAGS))
GIT = git
TAR = tar
MKDIR = mkdir
TOUCH = touch
CP = cp
RM = rm
LN = ln
FIND = find
INSTALL = install
MKTEMP = mktemp
STRIP = strip
PANDOC = pandoc
SED = sed
RPMBUILD = rpmbuild
GIT2DEBCL = ./buildtools/git2debcl
PKGCONFIG = pkg-config
ifeq ($(shell id -u),0)
FAKEROOT ?=
endif
CP ?= cp
FAKEROOT ?= fakeroot
FIND ?= find
GIT ?= git
GIT2DEBCL ?= buildtools/git2debcl
INSTALL ?= install
LN ?= ln
MKDIR ?= mkdir
MKTEMP ?= mktemp
MV ?= mv
RM ?= rm
RPMBUILD ?= rpmbuild
RPMBUILD_FLAGS ?=
SED ?= sed
STRIP ?= strip
TAR ?= tar
TOUCH ?= touch
BUILDDIR := build
GITHUB_REPO ?= "https://github.com/trapexit/mergerfs"
DEFAULT_TARGET := debian:13.amd64
ifndef GIT_REPO
GIT_REPO = 0
ifneq ($(shell $(GIT) --version 2> /dev/null),)
ifeq ($(shell test -e .git; echo $$?),0)
GIT_REPO = 1
endif
endif
endif
USE_XATTR ?= 1
USE_XATTR = 1
UGID_USE_RWLOCK = 0
ifdef SANITIZE
ifeq ($(SANITIZE),1)
override SANITIZE := -fsanitize=address,undefined,leak
else ifeq ($(filter -fsanitize=%,$(SANITIZE)),)
override SANITIZE := -fsanitize=$(SANITIZE)
endif
endif
COMMON_OPT_FLAGS += \
-fstack-protector-strong \
-Wextra \
-Wno-unused-parameter
DEBUG_OPT_FLAGS += \
-O0 \
-g3 \
-fno-omit-frame-pointer \
$(SANITIZE)
ifdef RELEASE
OPT_FLAGS := -O3 $(COMMON_OPT_FLAGS)
ifeq ($(DEBUG),1)
OPT_FLAGS := -O0 -g -fsanitize=undefined
else
OPT_FLAGS ?= $(DEBUG_OPT_FLAGS) $(COMMON_OPT_FLAGS)
OPT_FLAGS := -O2 -DNDEBUG
endif
ifdef STATIC
ifeq ($(STATIC),1)
STATIC_FLAGS := -static
else
STATIC_FLAGS :=
endif
ifdef LTO
ifeq ($(LTO),1)
LTO_FLAGS := -flto
else
LTO_FLAGS :=
endif
SRC := $(wildcard src/*.cpp)
OBJS := $(SRC:src/%.cpp=build/.objs/%.cpp.o)
DEPS := $(SRC:src/%.cpp=build/.objs/%.cpp.d)
SRC = $(wildcard src/*.cpp)
OBJS = $(SRC:src/%.cpp=build/.src/%.o)
DEPS = $(SRC:src/%.cpp=build/.src/%.d)
TESTS := $(wildcard tests/*.cpp)
TESTS_OBJS := $(filter-out build/.objs/mergerfs.cpp.o,$(OBJS))
TESTS_OBJS += $(TESTS:tests/%.cpp=build/.test_objs/%.cpp.o)
TESTS_DEPS := $(TESTS:tests/%.cpp=build/.test_objs/%.cpp.d)
TESTS = $(wildcard tests/*.cpp)
TESTS_OBJS = $(filter-out build/.src/mergerfs.o,$(OBJS))
TESTS_OBJS += $(TESTS:tests/%.cpp=build/.tests/%.o)
TESTS_DEPS = $(TESTS:tests/%.cpp=build/.tests/%.d)
TESTS_DEPS += $(DEPS)
MANPAGE := mergerfs.1
CPPFLAGS ?=
override CPPFLAGS += \
-D_FILE_OFFSET_BITS=64 \
-DBOOST_UNORDERED_DISABLE_PARALLEL_ALGORITHMS
CFLAGS ?= \
$(OPT_FLAGS) \
-Wall \
-Wno-unused-result \
-pipe
override CFLAGS += \
-MMD \
-MP
CXXFLAGS ?= \
$(OPT_FLAGS) \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Wall \
-Wpessimizing-move \
-Werror=pessimizing-move \
-Wredundant-move \
-Werror=redundant-move \
-Wno-unused-result \
-pipe
override CXXFLAGS += \
-std=c++20 \
-MMD \
-MP
override INC_FLAGS := \
-Isrc \
-Ivendored \
-Ivendored/libfuse/include
override MFS_FLAGS := \
-DUSE_XATTR=$(USE_XATTR)
override TESTS_FLAGS := \
-Isrc \
-Ivendored \
-Ivendored/acutest \
-DTESTS
MANPAGE = mergerfs.1
CFLAGS ?= ${OPT_FLAGS}
CFLAGS := ${CFLAGS} \
-Wall \
-Wno-unused-result
CXXFLAGS ?= ${OPT_FLAGS}
CXXFLAGS := \
${CXXFLAGS} \
-std=c++11 \
$(STATIC_FLAGS) \
$(LTO_FLAGS) \
-Wall \
-Wno-unused-result \
-MMD
FUSE_FLAGS = \
-Ilibfuse/include \
-D_FILE_OFFSET_BITS=64
MFS_FLAGS = \
-DUSE_XATTR=$(USE_XATTR) \
-DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK)
TESTS_FLAGS = \
-Isrc \
-DTESTS
LIBFUSE := vendored/libfuse/$(BUILDDIR)/libfuse.a
LDFLAGS ?=
LDLIBS := \
-lrt \
-pthread
override LDLIBS += \
$(LIBFUSE)
ifeq ($(CXX),g++)
GCC_VERSION := $(shell $(CXX) -dumpversion | cut -f1 -d.)
ifeq ($(shell test $(GCC_VERSION) -lt 9; echo $$?),0)
override LDLIBS += -lstdc++fs
endif
endif
LDFLAGS := \
${LDFLAGS} \
-pthread \
-lrt
# https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
DESTDIR ?=
PREFIX ?= /usr/local
EXEC_PREFIX ?= $(PREFIX)
DATAROOTDIR ?= $(PREFIX)/share
DATADIR ?= $(DATAROOTDIR)
BINDIR ?= $(EXEC_PREFIX)/bin
SBINDIR ?= $(EXEC_PREFIX)/sbin
LIBDIR ?= $(EXEC_PREFIX)/lib
MANDIR ?= $(DATAROOTDIR)/man
MAN1DIR ?= $(MANDIR)/man1
INSTALLBINDIR ?= $(DESTDIR)$(BINDIR)
INSTALLSBINDIR ?= $(DESTDIR)$(SBINDIR)
INSTALLLIBDIR ?= $(DESTDIR)$(LIBDIR)/mergerfs
INSTALLMAN1DIR ?= $(DESTDIR)$(MAN1DIR)
DESTDIR =
PREFIX = /usr/local
EXEC_PREFIX = $(PREFIX)
DATAROOTDIR = $(PREFIX)/share
DATADIR = $(DATAROOTDIR)
BINDIR = $(EXEC_PREFIX)/bin
SBINDIR = $(EXEC_PREFIX)/sbin
LIBDIR = $(EXEC_PREFIX)/lib
MANDIR = $(DATAROOTDIR)/man
MAN1DIR = $(MANDIR)/man1
INSTALLBINDIR = $(DESTDIR)$(BINDIR)
INSTALLSBINDIR = $(DESTDIR)$(SBINDIR)
INSTALLLIBDIR = $(DESTDIR)$(LIBDIR)/mergerfs
INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR)
.PHONY: all
all: libfuse $(BUILDDIR)/mergerfs $(BUILDDIR)/fsck.mergerfs $(BUILDDIR)/mergerfs.collect-info
all: mergerfs
.PHONY: help
help:
@echo "usage: make ARG\n"
@echo "USE_XATTR=0 - build program without xattrs functionality"
@echo "STATIC=1 - build static binary"
@echo "LTO=1 - build with link time optimization"
@echo "SANITIZE=1 - build with sanitizers (address,undefined,leak)"
@echo "SANITIZE=list - build with custom sanitizers (comma separated)"
@echo "CLEANUP=1 - cleanup images between release build process"
@echo "PKGDIR=/dir/ - location for release build pkgs"
@echo "GITREF=gitref - gitref to use for release builds"
@echo "usage: make\n"
@echo "make USE_XATTR=0 - build program without xattrs functionality"
@echo "make STATIC=1 - build static binary"
@echo "make LTO=1 - build with link time optimization"
objects: version build/stamp
$(MAKE) $(OBJS)
$(BUILDDIR)/mergerfs: $(LIBFUSE) src/version.hpp $(OBJS)
$(CXX) $(CXXFLAGS) $(INC_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LDLIBS)
tests-objects:
$(MAKE) $(TESTS_OBJS)
$(BUILDDIR)/fsck.mergerfs: $(BUILDDIR)/mergerfs
$(LN) -sf "mergerfs" $@
build/mergerfs: libfuse objects
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS)
$(BUILDDIR)/mergerfs.collect-info: $(BUILDDIR)/mergerfs
$(LN) -sf "mergerfs" $@
build/tests: build/mergerfs tests-objects
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(TESTS_OBJS) -o $@ libfuse/build/libfuse.a $(LDFLAGS)
$(BUILDDIR)/tests: $(BUILDDIR)/mergerfs $(TESTS_OBJS)
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(INC_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) $(TESTS_OBJS) -o $@ $(LDFLAGS) $(LDLIBS)
mergerfs: build/mergerfs
.PHONY: libfuse
libfuse: $(LIBFUSE)
$(MAKE) -C vendored/libfuse
tests: build/tests
$(LIBFUSE):
$(MAKE) -C vendored/libfuse $(BUILDDIR)/libfuse.a RELEASE=$(RELEASE)
tests: $(BUILDDIR)/tests
.PHONY:
changelog:
ifdef GIT_REPO
ifeq ($(GIT_REPO),1)
$(GIT2DEBCL) --name mergerfs > ChangeLog
else
@echo "WARNING: need git repo to generate ChangeLog"
endif
.PHONY: version
version: src/version.hpp
src/version.hpp:
version:
./buildtools/update-version
$(BUILDDIR)/stamp:
$(MKDIR) -p $(BUILDDIR)/.objs
$(MKDIR) -p $(BUILDDIR)/.test_objs
build/stamp:
$(MKDIR) -p build/.src build/.tests
$(TOUCH) $@
$(BUILDDIR)/.objs/%.cpp.o: src/%.cpp $(BUILDDIR)/stamp
$(CXX) $(CXXFLAGS) $(INC_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
build/.src/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
$(BUILDDIR)/.test_objs/%.cpp.o: tests/%.cpp | $(BUILDDIR)/stamp
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(INC_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
build/.tests/%.o: tests/%.cpp
$(CXX) $(CXXFLAGS) $(TESTS_FLAGS) $(FUSE_FLAGS) $(MFS_FLAGS) $(CPPFLAGS) -c $< -o $@
$(BUILDDIR)/preload.so: $(BUILDDIR)/stamp tools/preload.c
$(CC) -shared -fPIC $(CFLAGS) -o $@ tools/preload.c
build/preload.so: build/stamp tools/preload.c
$(CC) -shared -fPIC $(CFLAGS) $(CPPFLAGS) -o $@ tools/preload.c
preload: $(BUILDDIR)/preload.so
preload: build/preload.so
.PHONY: clean
clean: rpm-clean
$(RM) -rf $(BUILDDIR)
$(RM) -rf build
$(FIND) . -name "*~" -delete
$(MAKE) -C vendored/libfuse clean
$(MAKE) -C libfuse clean
.PHONY: distclean
distclean: clean
ifdef GIT_REPO
ifeq ($(GIT_REPO),1)
$(GIT) clean -xfd
endif
.PHONY: install
install: install-base install-mount-tools install-preload install-man
.PHONY: install-base
install-base: all
install-base: build/mergerfs
$(MKDIR) -p "$(INSTALLBINDIR)"
$(INSTALL) -v -m 0755 "$(BUILDDIR)/mergerfs" "$(INSTALLBINDIR)/mergerfs"
$(LN) -fs "mergerfs" "${INSTALLBINDIR}/fsck.mergerfs"
$(LN) -fs "mergerfs" "${INSTALLBINDIR}/mergerfs.collect-info"
$(INSTALL) -v -m 0755 build/mergerfs "$(INSTALLBINDIR)/mergerfs"
.PHONY: install-mount-tools
install-mount-tools: install-base
$(MKDIR) -p "$(INSTALLBINDIR)"
$(MAKE) -C vendored/libfuse install
$(MAKE) -C libfuse install
.PHONY: install-man
install-man: man/$(MANPAGE)
install-man: $(MANPAGE)
$(MKDIR) -p "$(INSTALLMAN1DIR)"
$(INSTALL) -v -m 0644 "man/$(MANPAGE)" "$(INSTALLMAN1DIR)/$(MANPAGE)"
.PHONY: install-preload
install-preload: preload
$(MKDIR) -p "$(INSTALLLIBDIR)"
$(INSTALL) -v -m 444 "$(BUILDDIR)/preload.so" "$(INSTALLLIBDIR)/preload.so"
$(INSTALL) -v -m 444 "build/preload.so" "$(INSTALLLIBDIR)/preload.so"
.PHONY: install-strip
install-strip: install-base
$(STRIP) "$(INSTALLBINDIR)/mergerfs"
.PHONY: uninstall
uninstall: uninstall-base uninstall-mount.mergerfs uninstall-preload uninstall-man
uninstall: uninstall-base uninstall-mount.mergerfs uninstall-man
uninstall-base:
$(RM) -f "$(INSTALLBINDIR)/mergerfs"
$(RM) -f "$(INSTALLBINDIR)/fsck.mergerfs"
$(RM) -f "$(INSTALLBINDIR)/mergerfs.collect-info"
uninstall-mount.mergerfs:
$(RM) -f "$(INSTALLBINDIR)/mount.mergerfs"
@ -292,11 +210,17 @@ uninstall-mount.mergerfs:
uninstall-man:
$(RM) -f "$(INSTALLMAN1DIR)/$(MANPAGE)"
uninstall-preload:
$(RM) -f "$(INSTALLLIBDIR)/preload.so"
$(MANPAGE): README.md
ifneq ($(shell $(PANDOC) --version 2> /dev/null),)
$(PANDOC) -s -t man -o "man/$(MANPAGE)" README.md
else
$(warning "pandoc does not appear available: unable to build manpage")
endif
man: $(MANPAGE)
.PHONY: tarball
tarball: changelog version
tarball: man changelog version
$(eval VERSION := $(shell cat VERSION))
$(eval VERSION := $(subst -,_,$(VERSION)))
$(eval FILENAME := mergerfs-$(VERSION))
@ -306,38 +230,29 @@ tarball: changelog version
$(TAR) --exclude=.git -cz -C $(TMPDIR) -f $(FILENAME).tar.gz $(FILENAME)
$(RM) -rf $(TMPDIR)
.PHONY: debian-changelog
debian-changelog:
ifdef GIT_REPO
ifeq ($(GIT_REPO),1)
$(GIT2DEBCL) --name mergerfs > debian/changelog
else
$(CP) -v ChangeLog debian/changelog
$(eval DISTRO := $(shell lsb_release -i -s | tr '[:upper:]' '[:lower:]'))
$(eval CODENAME := $(shell lsb_release -c -s | tr '[:upper:]' '[:lower:]'))
sed -i 's/~unknown-unknown/~$(DISTRO)-$(CODENAME)/g' debian/changelog
sed -i 's/ unknown; / $(CODENAME); /g' debian/changelog
cp ChangeLog debian/changelog
endif
.PHONY: signed-deb
signed-deb:
$(MAKE) distclean
$(MAKE) debian-changelog
$(FAKEROOT) dpkg-buildpackage -nc
# dpkg-source -b .
dpkg-buildpackage -nc
.PHONY: deb
deb:
$(MAKE) distclean
$(MAKE) debian-changelog
$(MAKE) version
$(FAKEROOT) dpkg-buildpackage -nc -uc -us
$(MKDIR) -p ./$(BUILDDIR)/pkgs/
$(MV) -v ../mergerfs*deb ./$(BUILDDIR)/pkgs/
# dpkg-source -b .
dpkg-buildpackage -nc -uc -us
.PHONY: rpm-clean
rpm-clean:
$(RM) -rf rpmbuild
.PHONY: rpm
rpm: tarball
$(eval VERSION := $(shell cat VERSION))
$(eval VERSION := $(subst -,_,$(VERSION)))
@ -345,65 +260,15 @@ rpm: tarball
$(SED) 's/__VERSION__/$(VERSION)/g' mergerfs.spec > \
rpmbuild/SOURCES/mergerfs.spec
cp -ar mergerfs-$(VERSION).tar.gz rpmbuild/SOURCES
$(RPMBUILD) $(RPMBUILD_FLAGS) -ba rpmbuild/SOURCES/mergerfs.spec \
$(RPMBUILD) -ba rpmbuild/SOURCES/mergerfs.spec \
--define "_topdir $(CURDIR)/rpmbuild"
.PHONY: install-build-pkgs
install-build-pkgs:
./buildtools/install-build-pkgs
.PHONY: install-build-tools
install-build-tools:
./buildtools/install-build-tools
define build_release
$(eval GITREF ?= $(shell git describe --exact-match --tags HEAD 2>/dev/null || git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD))
@echo "GITREF=$(GITREF)"
./buildtools/build-release \
--target=$(1) \
$(if $(CLEANUP),--cleanup) \
$(if $(PKGDIR),--pkgdirpath=$(PKGDIR)) \
--git-repo=$(if $(REMOTE_REPO),$(GITHUB_REPO),".") \
--branch=$(GITREF)
endef
.PHONY: release release-all
.PHONY: release-amd64 release-arm64 release-armhf release-riscv64
.PHONY: release-sample release-static release-tarball release-installer
release:
$(MAKE) RELEASE=1 CPPFLAGS="$(CPPFLAGS) -DNDEBUG" all
release-all:
$(call build_release,"all")
release-sample:
$(if $(TARGET),,$(eval TARGET := $(shell ./buildtools/detect-local-target 2>/dev/null)))
$(call build_release,$(if $(TARGET),$(TARGET),$(DEFAULT_TARGET)))
release-amd64:
$(call build_release,"amd64")
release-arm64:
$(call build_release,"arm64")
release-armhf:
$(call build_release,"armhf")
release-riscv64:
$(call build_release,"riscv64")
release-static:
$(call build_release,"static")
release-tarball:
$(call build_release,"tarball")
release-installer:
$(call build_release,"installer")
container:
$(eval GITREF ?= $(shell git describe --exact-match --tags HEAD 2>/dev/null || git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD))
@echo "GITREF=$(GITREF)"
./buildtools/build-containerimage "$(GITREF)"
.PHONY: tags
tags:
rm -fv TAGS
find . -name "*.c" -print | etags --append -
find . -name "*.h" -print | etags --append -
find . -name "*.cpp" -print | etags --append -
find . -name "*.hpp" -print | etags --append -
.PHONY: libfuse
libfuse:
$(MAKE) DEBUG=$(DEBUG) -C libfuse
-include $(DEPS)

2788
README.md

File diff suppressed because it is too large Load diff

View file

@ -1,16 +0,0 @@
#!/bin/sh
GIT_BRANCH="${1:-master}"
set -x
podman \
build \
--squash \
--no-cache \
--force-rm \
--build-arg="GIT_REPO=file:///mnt" \
--build-arg="BRANCH=${GIT_BRANCH}" \
-v "${PWD}":/mnt:ro \
-f "buildtools/containerimage/Containerfile" \
--tag "ghcr.io/trapexit/mergerfs:${GIT_BRANCH}" \
buildtools/

View file

@ -1,76 +0,0 @@
#!/bin/sh
set -e
if [ -e /tmp/build-env ]; then
. /tmp/build-env
fi
rpmbuild_flags()
{
case "$(command -v "${CXX:-g++}")" in
/opt/rh/*)
printf '%s' '--undefine _annotated_build'
;;
esac
}
if [ $# -ne 2 ]; then
echo "usage: $0 <branch> <git_repo>"
echo "argv: $@"
echo "argc: $#"
exit 1
fi
GIT_REPO="${1}"
BRANCH="${2}"
BUILDDIR="/tmp/build"
echo "Clone source from ${GIT_REPO} to ${BUILDDIR}"
git \
clone \
--single-branch \
--branch="${BRANCH}" \
"${GIT_REPO}" \
"${BUILDDIR}"
cd "${BUILDDIR}"
git log HEAD^1..
mkdir "/build"
if [ -e /usr/bin/apt-get ]; then
make deb
elif [ -e /usr/bin/dnf ]; then
make RPMBUILD_FLAGS="$(rpmbuild_flags)" rpm
elif [ -e /usr/bin/yum ]; then
make RPMBUILD_FLAGS="$(rpmbuild_flags)" rpm
elif [ -e /sbin/apk ]; then
echo "NOT YET SUPPORTED"
exit 1
elif [ -e /usr/sbin/pkg ]; then
echo "NOT YET SUPPORTED"
exit 1
elif [ -e /usr/bin/pacman ]; then
make tarball
else
echo "NOT YET SUPPORTED"
exit 1
fi
echo "Copy packages to host..."
if [ -e /usr/bin/pacman ]; then
find "${BUILDDIR}" \
-type f \
-name "*.tar.gz" \
-exec cp -v {} /build/ \;
else
find "${BUILDDIR}" \
-type f \
\( -name "*.deb" -or -name "*.rpm" \) \
-not -name "*dbgsym*" \
-not -name "*sym*" \
-not -name "*src.rpm" \
-exec cp -v {} /build/ \;
fi
exit 0

View file

@ -1,178 +0,0 @@
#!/usr/bin/env python3
import subprocess
import sys
import os
import argparse
import time
def build(git_repo,
branch,
containerfile,
pkgdirpath):
timestamp = time.time_ns()
args = ['podman',
'build',
'--pull=always',
'--force-rm']
if os.path.exists(git_repo):
git_repo = os.path.realpath(git_repo)
args += ['-v',f'{git_repo}:/tmp/mergerfs.git:ro:z']
args += ['--build-arg=GIT_REPO=file:///tmp/mergerfs.git']
else:
args += [f'--build-arg=GIT_REPO={git_repo}']
os.makedirs(pkgdirpath,exist_ok=True)
args += ['-v',f'{os.path.realpath(pkgdirpath)}:/pkgs:ro']
args += ['-o',pkgdirpath,
'-f',containerfile,
f'--build-arg=BRANCH={branch}',
f'--build-arg=BUILD_TIMESTAMP={timestamp}',
'buildtools/']
# TODO: Capture output and write to log
print(args)
rv = subprocess.run(args)
report_filepath = os.path.join(pkgdirpath,"build-report.txt")
with open(report_filepath,"a+") as f:
build = os.path.basename(containerfile)
f.write(build + ": ")
f.write(f"branch={branch}; ")
f.write(f"timestamp={timestamp}; ")
f.write("rv=")
if rv.returncode == 0:
f.write("success;")
else:
f.write("fail;")
f.write("\n")
def setup():
# Detect distribution
if os.path.exists('/usr/bin/apt-get'):
args = ['sudo',
'apt-get',
'install',
'-fy',
'qemu-user-static',
'qemu-user-binfmt']
elif os.path.exists('/usr/bin/pacman'):
args = ['sudo',
'pacman',
'-Sy',
'--noconfirm',
'qemu-user-static']
else:
print("Unsupported distribution for setup")
sys.exit(1)
print(args)
subprocess.run(args)
setup_binfmt()
def setup_binfmt():
"""Register qemu-user-static binfmt handlers (needed on Arch, etc.)."""
binfmt_conf = """\
:qemu-aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:/usr/bin/qemu-aarch64-static:F
:qemu-arm:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:/usr/bin/qemu-arm-static:F
:qemu-armeb:M::\\x7fELF\\x01\\x02\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:/usr/bin/qemu-armeb-static:F
:qemu-riscv64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xf3\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:/usr/bin/qemu-riscv64-static:F
:qemu-i386:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x03\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:/usr/bin/qemu-i386-static:F
"""
conf_path = '/etc/binfmt.d/qemu-static.conf'
print(f"Writing {conf_path}")
try:
with open(conf_path, 'w') as f:
f.write(binfmt_conf)
except PermissionError:
print(f"Permission denied writing {conf_path}; trying with sudo...")
subprocess.run(['sudo', 'tee', conf_path],
input=binfmt_conf.encode(), check=True)
print("Restarting systemd-binfmt...")
subprocess.run(['sudo', 'systemctl', 'restart', 'systemd-binfmt'])
def podman_cleanup():
args = ['podman',
'system',
'prune',
'-af']
print(args)
subprocess.run(args)
def parse_args():
p = argparse.ArgumentParser()
p.add_argument('--target',
default='debian:13.amd64')
p.add_argument('--pkgdirpath',
default='build/pkgs/')
p.add_argument('--branch',
default='master')
p.add_argument('--setup',
required=False,
action='store_true')
p.add_argument('--cleanup',
required=False,
action='store_true')
p.add_argument('--git-repo',
required=False,
type=str)
return p.parse_args()
def should_skip(filename):
if filename.endswith('~'):
return True
return False
def main():
args = parse_args()
print(args)
if args.setup:
setup()
sys.exit(0)
if not args.git_repo:
print("error: the following arguments are required: --git-repo")
sys.exit(1)
containerfiles = []
basepath = 'buildtools/containerfiles'
if os.path.exists(f'{basepath}/{args.target}'):
containerfiles.append(f'{basepath}/{args.target}')
elif args.target == 'all':
for root,dirnames,filenames in os.walk(basepath):
filenames.sort()
for filename in filenames:
if should_skip(filename):
continue
containerfile = f'buildtools/containerfiles/{filename}'
containerfiles.append(containerfile)
else:
for root,dirnames,filenames in os.walk(basepath):
filenames.sort()
for filename in filenames:
if args.target not in filename:
continue
if should_skip(filename):
continue
containerfile = f'buildtools/containerfiles/{filename}'
containerfiles.append(containerfile)
for containerfile in containerfiles:
if args.cleanup:
podman_cleanup()
build(git_repo=args.git_repo,
branch=args.branch,
containerfile=containerfile,
pkgdirpath=args.pkgdirpath)
sys.exit(0)
if __name__ == '__main__':
main()

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 debian:11 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 debian:11 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf debian:11 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=i386 debian:11 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 debian:12 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 debian:12 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf debian:12 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=i386 debian:12 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 debian:13 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 debian:13 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf debian:13 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=i386 debian:13 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 debian:13 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 fedora:40 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 fedora:40 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 fedora:41 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 fedora:41 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 fedora:42 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 fedora:42 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 fedora:43 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 fedora:43 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 fedora:44 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 fedora:44 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 quay.io/rockylinux/rockylinux:10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 quay.io/rockylinux/rockylinux:10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 quay.io/rockylinux/rockylinux:8 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 quay.io/rockylinux/rockylinux:8 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 quay.io/rockylinux/rockylinux:9 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 quay.io/rockylinux/rockylinux:9 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,15 +0,0 @@
FROM --platform=linux/amd64 alpine:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN git clone --single-branch --branch="${BRANCH}" ${GIT_REPO} /tmp/mergerfs
WORKDIR /tmp/mergerfs
RUN make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp -j$(nproc) install
RUN mkdir /build
RUN /tmp/usr/local/bin/mergerfs --version | head -n1 | cut -c 11- | tee /tmp/version
RUN tar cvfz /build/mergerfs-$(cat /tmp/version)-static-linux_amd64.tar.gz --directory=/tmp usr sbin
FROM scratch
COPY --from=build /build/ /

View file

@ -1,15 +0,0 @@
FROM --platform=linux/arm64 alpine:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN git clone --single-branch --branch="${BRANCH}" ${GIT_REPO} /tmp/mergerfs
WORKDIR /tmp/mergerfs
RUN make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp -j$(nproc) install
RUN mkdir /build
RUN /tmp/usr/local/bin/mergerfs --version | head -n1 | cut -c 11- | tee /tmp/version
RUN tar cvfz /build/mergerfs-$(cat /tmp/version)-static-linux_arm64.tar.gz --directory=/tmp usr sbin
FROM scratch
COPY --from=build /build/ /

View file

@ -1,15 +0,0 @@
FROM --platform=linux/armhf alpine:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN git clone --single-branch --branch="${BRANCH}" ${GIT_REPO} /tmp/mergerfs
WORKDIR /tmp/mergerfs
RUN make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp -j$(nproc) install
RUN mkdir /build
RUN /tmp/usr/local/bin/mergerfs --version | head -n1 | cut -c 11- | tee /tmp/version
RUN tar cvfz /build/mergerfs-$(cat /tmp/version)-static-linux_armhf.tar.gz --directory=/tmp usr sbin
FROM scratch
COPY --from=build /build/ /

View file

@ -1,15 +0,0 @@
FROM --platform=linux/i386 alpine:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN git clone --single-branch --branch="${BRANCH}" ${GIT_REPO} /tmp/mergerfs
WORKDIR /tmp/mergerfs
RUN make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp -j$(nproc) install
RUN mkdir /build
RUN /tmp/usr/local/bin/mergerfs --version | head -n1 | cut -c 11- | tee /tmp/version
RUN tar cvfz /build/mergerfs-$(cat /tmp/version)-static-linux_i386.tar.gz --directory=/tmp usr sbin
FROM scratch
COPY --from=build /build/ /

View file

@ -1,14 +0,0 @@
ARG BUILD_TIMESTAMP=0
FROM --platform=linux/amd64 ubuntu:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs && \
DEBIAN_FRONTEND=noninteractive apt-get -qy --no-install-suggests --no-install-recommends install \
makeself
RUN mkdir -p /tmp/mergerfs/
RUN ls -lhd /pkgs
RUN cp -v /pkgs/*static*.gz /tmp/mergerfs/
RUN mkdir -p /build
RUN makeself /tmp/mergerfs/ /build/mergerfs-installer.run "mergerfs" echo "foo"
FROM scratch
COPY --from=build /build/ /

View file

@ -1,15 +0,0 @@
FROM --platform=linux/riscv64 alpine:latest as build
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN git clone --single-branch --branch="${BRANCH}" ${GIT_REPO} /tmp/mergerfs
WORKDIR /tmp/mergerfs
RUN make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp -j$(nproc) install
RUN mkdir /build
RUN /tmp/usr/local/bin/mergerfs --version | head -n1 | cut -c 11- | tee /tmp/version
RUN tar cvfz /build/mergerfs-$(cat /tmp/version)-static-linux_riscv64.tar.gz --directory=/tmp usr sbin
FROM scratch
COPY --from=build /build/ /

View file

@ -1,17 +0,0 @@
FROM alpine:latest as tarball
COPY install-build-pkgs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG BRANCH=master
ARG GIT_REPO
RUN git clone --single-branch "${GIT_REPO}" /tmp/mergerfs --branch="${BRANCH}"
RUN cd /tmp/mergerfs && make version tarball
RUN mkdir /build
RUN cp -v /tmp/mergerfs/*.tar.gz /build/
FROM scratch
COPY --from=tarball /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 ubuntu:22.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 ubuntu:22.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf ubuntu:22.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 ubuntu:22.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 ubuntu:24.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 ubuntu:24.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf ubuntu:24.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 ubuntu:24.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 ubuntu:25.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 ubuntu:25.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf ubuntu:25.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 ubuntu:25.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 ubuntu:25.10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 ubuntu:25.10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf ubuntu:25.10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 ubuntu:25.10 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=amd64 ubuntu:26.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=arm64 ubuntu:26.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=armhf ubuntu:26.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,10 +0,0 @@
FROM --platform=riscv64 ubuntu:26.04 as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs $GIT_REPO $BRANCH
FROM scratch
COPY --from=build /build/ /

View file

@ -1,19 +0,0 @@
FROM --platform=linux/amd64 alpine:latest as build
ARG GIT_REPO
ARG BRANCH
RUN <<EOF
apk add git gcc g++ make linux-headers
git clone --single-branch --branch="${BRANCH}" "${GIT_REPO}" /tmp/mergerfs
cd /tmp/mergerfs
make NDEBUG=1 LTO=1 STATIC=1 DESTDIR=/tmp/install -j$(nproc) install
tar cvfz /tmp/mergerfs.tgz --directory=/tmp/install usr sbin
EOF
FROM --platform=linux/amd64 alpine:latest
RUN --mount=from=build,source=/tmp/mergerfs.tgz,target=/tmp/mergerfs.tgz <<EOF
tar xvf /tmp/mergerfs.tgz -C /
EOF
ENTRYPOINT ["/usr/local/bin/mergerfs"]
CMD ["--help"]

View file

@ -1,119 +0,0 @@
#!/bin/bash
# Detects local OS and maps to containerfiles target
# Returns target if found in buildtools/containerfiles/, empty string otherwise
set -euo pipefail
CONTAINERFILES_DIR="buildtools/containerfiles"
# Detect system architecture and map to containerfiles format
detect_arch() {
local arch
arch=$(uname -m)
case "$arch" in
x86_64) echo "amd64" ;;
aarch64) echo "arm64" ;;
armv7l) echo "armhf" ;;
i686|i386) echo "i386" ;;
riscv64) echo "riscv64" ;;
*) echo "" ;;
esac
}
# Detect distro and version from os-release
detect_distro() {
local os_release="${1:-}"
if [[ ! -r "$os_release" ]]; then
return 1
fi
# Source the file safely - ID and VERSION_ID are environment variables
. "$os_release"
local distro="$ID"
local version="$VERSION_ID"
# Map distro ID to containerfiles naming convention
case "$distro" in
ubuntu|debian|fedora) ;;
rocky|rhel|centos|almalinux) distro="rockylinux" ;;
*)
# Fallback to ID_LIKE for derivatives
if [[ -n "${ID_LIKE:-}" ]]; then
case "$ID_LIKE" in
*ubuntu*) distro="ubuntu" ;;
*debian*) distro="debian" ;;
*fedora*) distro="fedora" ;;
esac
fi
;;
esac
# Only return if we have valid distro and version
if [[ -n "$distro" && -n "$version" ]]; then
echo "$distro:$version"
else
return 1
fi
}
# Try to find a matching containerfile target
find_containerfile() {
local target="$1"
local containerfile="${CONTAINERFILES_DIR}/${target}"
# Direct match
if [[ -d "$containerfile" || -f "$containerfile" ]]; then
echo "$target"
return 0
fi
return 1
}
# Main detection logic
main() {
local arch
# Detect architecture
arch=$(detect_arch)
if [[ -z "$arch" ]]; then
echo "WARNING: Could not detect system architecture" >&2
exit 1
fi
# Try to detect distro from multiple locations
local distro_ver
distro_ver=$(detect_distro "/etc/os-release") || \
distro_ver=$(detect_distro "/usr/lib/os-release") || {
echo "WARNING: Could not detect distro from os-release" >&2
exit 1
}
# Build target string
local target="${distro_ver}.${arch}"
# Try to find matching containerfile
if find_containerfile "$target"; then
exit 0
fi
# Try with partial version matching (e.g., 25.10 → 25)
local distro="${distro_ver%%:*}"
local version="${distro_ver##*:}"
# Strip last minor version number and try again
local short_version="${version%.*}"
if [[ -n "$short_version" ]]; then
target="${distro}:${short_version}.${arch}"
if find_containerfile "$target"; then
exit 0
fi
fi
# No match found
echo "WARNING: No containerfile found for target: ${distro_ver}.${arch}" >&2
exit 1
}
main "$@"

View file

@ -1,27 +0,0 @@
#!/bin/sh
input_file="${1}"
while IFS= read -r line || [ -n "$line" ]; do
# Skip empty lines
if [ -z "$line" ]; then
continue
fi
image=$(echo "$line" | cut -d' ' -f1)
platform=$(echo "$line" | cut -d' ' -f2-)
echo "${image} ${platform}"
cat <<EOF > "containerfiles/${image##*/}.${platform}"
FROM --platform=${platform} ${image} as build
COPY install-build-pkgs build-mergerfs /tmp/
RUN /tmp/install-build-pkgs
ARG BUILD_TIMESTAMP=0
ARG GIT_REPO
ARG BRANCH
RUN /tmp/build-mergerfs \$GIT_REPO \$BRANCH
FROM scratch
COPY --from=build /build/ /
EOF
done < "$input_file"

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env python
# Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
@ -14,189 +14,99 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Default values
NAME=""
VERSION="::guess::"
DISTRO="::guess::"
CODENAME="::guess::"
URGENCY="medium"
import sys
import subprocess
import argparse
# Function to display usage
usage() {
cat << EOF
Usage: $0 --name NAME [OPTIONS]
def call(args):
return subprocess.Popen(args,stdout=subprocess.PIPE).communicate()[0].decode()
Generated debian/changelog from git log
def git_tags():
args = ["git", "tag", '-l']
tags = call(args)
tags = [[int(X) for X in tag.split(".")] for tag in tags.split()]
tags.sort()
tags.reverse()
tags = [".".join([str(X) for X in tag]) for tag in tags]
return tags
Options:
--name NAME Name of package (required)
--version VERSION Place in git history to include upto (default: ::guess::)
--distro DISTRO Distribution name (default: ::guess::)
--codename NAME Distribution codename (default: ::guess::)
--urgency URGENCY Urgency (default: medium)
-h, --help Show this help message
EOF
exit 1
}
def git_log(fromtag,totag):
args = ['git','log','--no-merges','--oneline',fromtag+'...'+totag]
return call(args).strip().split('\n')
# Parse command line arguments
while [ $# -gt 0 ]; do
case "$1" in
--name)
NAME="$2"
shift 2
;;
--version)
VERSION="$2"
shift 2
;;
--distro)
DISTRO="$2"
shift 2
;;
--codename)
CODENAME="$2"
shift 2
;;
--urgency)
URGENCY="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
def git_author_and_time(tag):
args = ['git','log','-1','--format=-- %an <%ae> %cD',tag]
return call(args).strip()
# Check required arguments
if [ -z "$NAME" ]; then
echo "Error: --name is required" >&2
usage
fi
def git_version():
args = ['git','describe','--always','--tags','--dirty']
return call(args).strip()
# Function to get git tags sorted in reverse order
git_tags() {
git tag -l | sort -rV
}
def guess_distro():
try:
args = ['lsb_release','-i','-s']
return call(args).strip().lower()
except:
return 'unknown'
# Function to get git log between two tags
git_log() {
local fromtag="$1"
local totag="$2"
git log --no-merges --oneline "${fromtag}...${totag}" 2>/dev/null
}
# Function to get author and time for a tag
git_author_and_time() {
local tag="$1"
git log -1 --format="-- %an <%ae> %cD" "$tag"
}
def guess_codename():
try:
args = ['lsb_release','-c','-s']
return call(args).strip().lower()
except:
return 'unknown'
# Function to get git version
git_version() {
git describe --always --tags --dirty 2>/dev/null || echo "unknown"
}
# Function to guess distribution
guess_distro() {
if command -v lsb_release >/dev/null 2>&1; then
lsb_release -i -s 2>/dev/null | tr '[:upper:]' '[:lower:]'
else
echo "unknown"
fi
}
def main():
parser = argparse.ArgumentParser(description='Generated debian/changelog from git log')
parser.add_argument('--name',type=str,help='Name of package',required=True)
parser.add_argument('--version',type=str,help='Place in git history to include upto',default='::guess::')
parser.add_argument('--distro',type=str,help='Distribution name',default='::guess::')
parser.add_argument('--codename',type=str,help='Distribution codename',default='::guess::')
parser.add_argument('--urgency',type=str,help='Urgency',default='medium')
# Function to guess codename
guess_codename() {
if command -v lsb_release >/dev/null 2>&1; then
lsb_release -c -s 2>/dev/null | tr '[:upper:]' '[:lower:]'
else
echo "unknown"
fi
}
args = parser.parse_args()
# Handle guessing of values
if [ "$DISTRO" = "::guess::" ]; then
DISTRO=$(guess_distro)
fi
if args.distro == '::guess::':
args.distro = guess_distro()
if [ "$CODENAME" = "::guess::" ]; then
CODENAME=$(guess_codename)
fi
if args.codename == '::guess::':
args.codename = guess_codename()
if [ "$VERSION" = "::guess::" ]; then
VERSION=$(git_version)
fi
versuffix = "~"+args.distro+"-"+args.codename
# Version suffix
VERSUFFIX="~${DISTRO}-${CODENAME}"
if args.version == '::guess::':
args.version = git_version()
# Get all tags
TAGS=$(git_tags)
tags = git_tags()
if args.version in tags:
idx = tags.index(args.version)
tags = tags[idx:]
tags = list(zip(tags,tags))
else:
tags = list(zip(tags,tags))
tags.insert(0,(args.version,'HEAD'))
# Create temporary file for tag pairs
TMPFILE=$(mktemp)
trap 'rm -f "$TMPFILE"' EXIT
for i in range(0,len(tags)):
tags[i] = (tags[i][0] + versuffix,tags[i][1])
# Check if version is in tags
if echo "$TAGS" | grep -q "^${VERSION}$"; then
# If version is a tag, start from that tag
echo "$TAGS" | awk -v ver="$VERSION" 'BEGIN{found=0} {if($0==ver)found=1; if(found)print}' > "$TMPFILE"
else
# If version is not a tag, use HEAD as starting point
echo "$VERSION HEAD" > "$TMPFILE"
echo "$TAGS" >> "$TMPFILE"
fi
# Process tags and generate changelog
PREV_TAG=""
PREV_REF=""
FIRST=1
while IFS= read -r line; do
if [ -z "$line" ]; then
continue
fi
# Handle the special case of VERSION HEAD
if [ "$line" = "$VERSION HEAD" ]; then
TAG="$VERSION"
REF="HEAD"
else
TAG="$line"
REF="$line"
fi
if [ -n "$PREV_TAG" ]; then
# Get log entries between current and previous tag
LOG_ENTRIES=$(git_log "$REF" "$PREV_REF")
# Skip if no changes
if [ -z "$LOG_ENTRIES" ] || [ "$LOG_ENTRIES" = "" ]; then
PREV_TAG="$TAG"
PREV_REF="$REF"
tag = tags[0]
for prev in tags[1:]:
lines = git_log(tag[1],prev[1])
if lines == ['']:
tag = prev
continue
fi
# Print package header
printf "%s (%s%s) %s; urgency=%s\n\n" "$NAME" "$PREV_TAG" "$VERSUFFIX" "$CODENAME" "$URGENCY"
print('{0} ({1}) {2}; urgency={3}\n'.format(args.name,tag[0],args.codename,args.urgency))
# Print each log entry
echo "$LOG_ENTRIES" | while IFS= read -r entry; do
if [ -n "$entry" ]; then
printf " * %s\n" "$entry"
fi
done
for line in lines:
print(" * " + line)
# Print author and time
AUTHOR_TIME=$(git_author_and_time "$PREV_REF")
printf "\n %s\n\n" "$AUTHOR_TIME"
fi
authorandtime = git_author_and_time(tag[1])
print(' {0}\n'.format(authorandtime))
PREV_TAG="$TAG"
PREV_REF="$REF"
done < "$TMPFILE"
tag = prev
if __name__ == "__main__":
main()

View file

@ -1,162 +1,46 @@
#!/bin/sh
set -e
BUILD_ENV=/tmp/build-env
write_gcc_env()
{
{
printf 'export CC=%s\n' "$1"
printf 'export CXX=%s\n' "$2"
} > "$BUILD_ENV"
}
write_toolset_env()
{
{
printf '. %s\n' "$1"
printf 'export CC=gcc\n'
printf 'export CXX=g++\n'
} > "$BUILD_ENV"
}
latest_apt_gxx()
{
apt-cache --names-only search '^g[+][+]-[0-9]' \
| sed -n 's/^\(g++-[0-9][0-9]*\) .*/\1/p' \
| sort -t- -k2,2V \
| tail -n 1
}
latest_dnf_toolset()
{
dnf -q list --showduplicates 'gcc-toolset-*-gcc-c++' 2>/dev/null \
| sed -n 's/^gcc-toolset-\([0-9][0-9]*\)-gcc-c++\..*/\1/p' \
| sort -V \
| tail -n 1
}
latest_yum_toolset()
{
yum -q list available 'devtoolset-*-gcc-c++' 2>/dev/null \
| sed -n 's/^devtoolset-\([0-9][0-9]*\)-gcc-c++\..*/\1/p' \
| sort -V \
| tail -n 1
}
version_gt()
{
highest="$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n 1)"
[ "$highest" = "$1" ] && [ "$1" != "$2" ]
}
check_cxx20()
{
cxx="${CXX:-g++}"
test_src=/tmp/mergerfs-cxx20-check.cpp
test_bin=/tmp/mergerfs-cxx20-check
cat > "$test_src" <<'EOF'
template <typename T>
concept Incrementable = requires(T value) { value + 1; };
static_assert(Incrementable<int>);
int main()
{
return 0;
}
EOF
if ! "$cxx" -std=c++20 "$test_src" -o "$test_bin" >/dev/null 2>&1; then
echo "error: $cxx does not support C++20" >&2
exit 1
fi
rm -f "$test_src" "$test_bin"
}
: > "$BUILD_ENV"
if [ -e /usr/bin/apt-get ]; then
export DEBIAN_FRONTEND=noninteractive
apt-get -qy update
cxx_pkg="$(latest_apt_gxx)"
if [ -n "$cxx_pkg" ]; then
gcc_pkg="gcc-${cxx_pkg#g++-}"
compiler_pkgs="$gcc_pkg $cxx_pkg"
write_gcc_env "$gcc_pkg" "$cxx_pkg"
else
compiler_pkgs="g++"
write_gcc_env gcc g++
fi
apt-get -qy --force-yes --no-install-suggests --no-install-recommends \
install \
ca-certificates \
build-essential \
dpkg-dev \
git \
$compiler_pkgs \
g++ \
debhelper \
lsb-release \
fakeroot
. "$BUILD_ENV"
check_cxx20
automake \
fakeroot \
libtool \
lsb-release
apt-get -qy --no-install-suggests --no-install-recommends install python
apt-get -qy --no-install-suggests --no-install-recommends install python3
elif [ -e /usr/bin/dnf ]; then
dnf -y update
toolset="$(latest_dnf_toolset)"
dnf -y install \
git rpm-build gcc-c++ make which libatomic
default_gxx_major="$(g++ -dumpversion | cut -f1 -d.)"
if [ -n "$toolset" ] && version_gt "$toolset" "$default_gxx_major"; then
dnf -y install \
"gcc-toolset-${toolset}-gcc" \
"gcc-toolset-${toolset}-gcc-c++"
write_toolset_env "/opt/rh/gcc-toolset-${toolset}/enable"
else
write_gcc_env gcc g++
fi
. "$BUILD_ENV"
check_cxx20
git rpm-build gcc-c++ make which python3 automake \
libtool gettext-devel
elif [ -e /usr/bin/yum ]; then
yum -y update
yum -y install \
git rpm-build gcc-c++ make which
yum -y install centos-release-scl || true
yum -y update
toolset="$(latest_yum_toolset)"
default_gxx_major="$(g++ -dumpversion | cut -f1 -d.)"
if [ -n "$toolset" ] && version_gt "$toolset" "$default_gxx_major"; then
yum -y install \
"devtoolset-${toolset}-gcc" \
"devtoolset-${toolset}-gcc-c++"
write_toolset_env "/opt/rh/devtoolset-${toolset}/enable"
else
write_gcc_env gcc g++
fi
. "$BUILD_ENV"
check_cxx20
elif [ -e /usr/bin/zypper ]; then
zypper update -y
zypper install -y \
git rpm-build gcc-c++ make which
write_gcc_env gcc g++
. "$BUILD_ENV"
check_cxx20
git rpm-build gcc-c++ make which \
python python-argparse \
automake libtool gettext-devel
elif [ -e /sbin/apk ]; then
apk add \
abuild git gcc g++ make \
linux-headers
write_gcc_env gcc g++
. "$BUILD_ENV"
check_cxx20
abuild git gcc g++ make autoconf \
automake libtool gettext-dev linux-headers
elif [ -e /usr/sbin/pkg ]; then
pkg install \
git gmake gcc
elif [ -e /usr/bin/pacman ]; then
pacman -Sy --noconfirm base-devel git fakeroot
write_gcc_env gcc g++
. "$BUILD_ENV"
check_cxx20
git gmake gcc autoconf automake libtool \
gettext-tools
fi
if [ ! -e /usr/bin/python ]; then
if [ -e /usr/bin/python3 ]; then
ln -s /usr/bin/python3 /usr/bin/python
elif [ -e /usr/bin/python2 ]; then
ln -s /usr/bin/python2 /usr/bin/python
fi
fi

View file

@ -1,32 +0,0 @@
#!/bin/sh
if [ "$(id -u)" -eq 0 ]; then
SUDO=
elif command -v sudo >/dev/null 2>&1; then
SUDO=sudo
elif command -v doas >/dev/null 2>&1; then
SUDO=doas
else
printf '%s\n' "error: need root privileges; run as root or install sudo/doas" >&2
exit 1
fi
if [ -e /usr/bin/apt-get ]; then
export DEBIAN_FRONTEND=noninteractive
${SUDO} apt-get -qy update
${SUDO} apt-get -qy --no-install-suggests --no-install-recommends install \
qemu-user-static \
podman
elif [ -e /usr/bin/dnf ]; then
${SUDO} dnf -y update
${SUDO} dnf -y install \
qemu-user-static \
podman
elif [ -e /sbin/apk ]; then
${SUDO} apk add \
python3 \
qemu-user-static \
podman
elif [ -e /usr/bin/pacman ]; then
${SUDO} pacman -Sy --noconfirm qemu-user-static podman
fi

View file

@ -1,39 +0,0 @@
debian:11 amd64
debian:11 arm64
debian:11 armhf
debian:11 i386
debian:12 amd64
debian:12 arm64
debian:12 armhf
debian:12 i386
debian:13 amd64
debian:13 arm64
debian:13 armhf
debian:13 i386
debian:13 riscv64
fedora:40 amd64
fedora:40 arm64
fedora:41 amd64
fedora:41 arm64
fedora:42 amd64
fedora:42 arm64
fedora:43 amd64
fedora:43 arm64
quay.io/rockylinux/rockylinux:10 amd64
quay.io/rockylinux/rockylinux:10 arm64
quay.io/rockylinux/rockylinux:8 amd64
quay.io/rockylinux/rockylinux:8 arm64
quay.io/rockylinux/rockylinux:9 amd64
quay.io/rockylinux/rockylinux:9 arm64
ubuntu:22.04 amd64
ubuntu:22.04 arm64
ubuntu:22.04 armhf
ubuntu:22.04 riscv64
ubuntu:24.04 amd64
ubuntu:24.04 arm64
ubuntu:24.04 armhf
ubuntu:24.04 riscv64
ubuntu:25.04 amd64
ubuntu:25.04 arm64
ubuntu:25.04 armhf
ubuntu:25.04 riscv64

View file

@ -9,12 +9,10 @@ if [ "${VERSION}" = "" ]; then
VERSION="unknown"
fi
echo "version = ${VERSION}"
echo -n "${VERSION}" > VERSION
grep -sq \"${VERSION}\" src/version.hpp
grep -q \"${VERSION}\" src/version.hpp
RV=$?
if [ $RV -ne 0 ]; then
echo "Writing 'src/version.hpp'"
echo "#pragma once" > src/version.hpp
echo "static const char MERGERFS_VERSION[] = \"${VERSION}\";" >> src/version.hpp
fi

1
debian/compat vendored Normal file
View file

@ -0,0 +1 @@
9

2
debian/control vendored
View file

@ -2,7 +2,7 @@ Source: mergerfs
Section: utils
Priority: optional
Maintainer: Antonio SJ Musumeci <trapexit@spawn.link>
Build-Depends: debhelper-compat (= 10)
Build-Depends: debhelper (>= 8.0.0)
Standards-Version: 3.9.4
Homepage: http://github.com/trapexit/mergerfs

11
debian/rules vendored
View file

@ -1,16 +1,11 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
%:
dh $@
override_dh_auto_build:
$(MAKE) release
dh $@ --parallel
override_dh_auto_install:
$(MAKE) \
DESTDIR=$(CURDIR)/debian/mergerfs \
PREFIX=/usr \
install
$(MAKE) DESTDIR=$(CURDIR)/debian/mergerfs PREFIX=/usr install

146
libfuse/Makefile Normal file
View file

@ -0,0 +1,146 @@
VERSION = 2.9.7-mergerfs_2.30.0
OS := $(shell uname -s)
ifeq ($(OS),Linux)
UTILS := utils
INSTALLUTILS := install-utils
else
UTILS :=
INSTALLUTILS :=
endif
ifeq ($(DEBUG),1)
OPT_FLAGS := -O0 -g -fsanitize=undefined
else
OPT_FLAGS := -O2
endif
ifeq ($(LTO),1)
LTO_FLAGS := -flto
else
LTO_FLAGS :=
endif
DESTDIR =
PREFIX = /usr/local
EXEC_PREFIX = $(PREFIX)
DATAROOTDIR = $(PREFIX)/share
DATADIR = $(DATAROOTDIR)
BINDIR = $(EXEC_PREFIX)/bin
SBINDIR = /sbin
MANDIR = $(DATAROOTDIR)/man
MAN1DIR = $(MANDIR)/man1
INSTALLBINDIR = $(DESTDIR)$(BINDIR)
INSTALLSBINDIR = $(DESTDIR)$(SBINDIR)
INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR)
AR ?= ar
SRC_C = \
lib/buffer.c \
lib/crc32b.c \
lib/debug.c \
lib/fuse.c \
lib/fuse_dirents.c \
lib/fuse_lowlevel.c \
lib/node.c \
lib/fuse_node.c \
lib/fuse_opt.c \
lib/fuse_session.c \
lib/fuse_signals.c \
lib/helper.c \
lib/mount.c
SRC_CPP = \
lib/format.cpp \
lib/os.cpp \
lib/cpu.cpp \
lib/fuse_config.cpp \
lib/fuse_loop.cpp \
lib/fuse_msgbuf.cpp
OBJS_C = $(SRC_C:lib/%.c=build/%.o)
OBJS_CPP = $(SRC_CPP:lib/%.cpp=build/%.o)
DEPS_C = $(SRC_C:lib/%.c=build/%.d)
DEPS_CPP = $(SRC_CPP:lib/%.cpp=build/%.d)
CFLAGS ?= \
$(OPT_FLAGS)
CFLAGS := \
${CFLAGS} \
$(LTO_FLAGS) \
-std=gnu99 \
-Wall \
-pipe \
-MMD
CXXFLAGS := \
${CXXFLAGS} \
$(LTO_FLAGS) \
-std=c++11 \
-Wall \
-pipe \
-MMD
FUSERMOUNT_DIR = $(BINDIR)
FUSE_FLAGS = \
-Iinclude \
-Ibuild \
-D_REENTRANT \
-D_FILE_OFFSET_BITS=64 \
-DPACKAGE_VERSION=\"$(VERSION)\" \
-DFUSERMOUNT_DIR=\"$(FUSERMOUNT_DIR)\"
LDFLAGS := \
${LDFLAGS} \
-lrt \
-pthread
all: build/libfuse.a $(UTILS)
build/config.h: build/stamp
ecfd/build | tee build/config.h
build/stamp:
mkdir -p build
touch $@
objects: build/config.h
$(MAKE) $(OBJS_C) $(OBJS_CPP)
build/libfuse.a: objects
${AR} rcs build/libfuse.a $(OBJS_C) $(OBJS_CPP)
utils: mergerfs-fusermount mount.mergerfs
build/mergerfs-fusermount: build/config.h util/fusermount.c lib/mount_util.c
$(CC) $(CFLAGS) $(FUSE_FLAGS) -Ilib -o build/mergerfs-fusermount util/fusermount.c lib/mount_util.c
mergerfs-fusermount: build/mergerfs-fusermount
build/mount.mergerfs: build/libfuse.a util/mount.mergerfs.c
$(CC) $(CFLAGS) $(FUSE_FLAGS) -o build/mount.mergerfs util/mount.mergerfs.c build/libfuse.a $(LDFLAGS)
mount.mergerfs: build/mount.mergerfs
build/%.o: lib/%.c
$(CC) $(CFLAGS) $(FUSE_FLAGS) -c $< -o $@
build/%.o: lib/%.cpp
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) -c $< -o $@
clean:
rm -rf build
distclean: clean
strip:
strip --strip-all build/mount.mergerfs
strip --strip-all build/mergerfs-fusermount
install-utils: mergerfs-fusermount mount.mergerfs strip
install -D build/mergerfs-fusermount "$(INSTALLBINDIR)/mergerfs-fusermount"
install -D build/mount.mergerfs "$(INSTALLSBINDIR)/mount.mergerfs"
chown root "$(INSTALLBINDIR)/mergerfs-fusermount"
chmod u+s "$(INSTALLBINDIR)/mergerfs-fusermount"
install: $(INSTALLUTILS)
.PHONY: objects strip utils install install-utils
-include $(DEPS_C) $(DEPS_CPP)

View file

@ -27,8 +27,7 @@ Because the high-level interface is path based, it is not possible to
delegate looking up by inode to the filesystem.
To work around this, currently a "noforget" option is provided, which
makes the library remember nodes until they are unlinked or otherwise
removed. This will make the NFS server happy, but also results in a
larger memory footprint for the filesystem. For this reason if the
filesystem is large (or the memory is small), then this option is not
recommended.
makes the library remember nodes forever. This will make the NFS
server happy, but also results in an ever growing memory footprint for
the filesystem. For this reason if the filesystem is large (or the
memory is small), then this option is not recommended.

View file

@ -1,7 +1,7 @@
/*
ISC License
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@ -14,11 +14,4 @@
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
namespace caps
{
int setup();
}
*/

16
libfuse/ecfd/README.md Normal file
View file

@ -0,0 +1,16 @@
# ecfd: embeddable C feature discovery
This is a simple script and set of tests to help with what would traditionally be the `configure` step of most C/C++. It is intended to be simple to be embedded into a project and only depends on the C compiler and /bin/sh.
## USAGE
First copy `ecfd` into your project. Next simply call the build script which will run the tests and output a `config.` style file to `stdout`. Compile errors will output to `stderr` which can be used to understand why they aren't working.
```
$ ./ecfd/build > include/config.h
```
## TESTS
Each test is in a single module. The build script will try to compile each module and on success will execute the program. If anything is printed to `stdout` it will be appended to the `#define` printed to the build script's `stdout`. If the compilation fails nothing will be printed. Look at the tests directory for examples.

32
libfuse/ecfd/build Executable file
View file

@ -0,0 +1,32 @@
#!/bin/sh
PWD=$(pwd)
BASEPATH="${PWD}/${0%/*}"
CC=${CC:-cc}
OUTPUT="/dev/null"
echo "#ifndef CONFIG_H_INCLUDED"
echo "#define CONFIG_H_INCLUDED"
echo
IFS=
for file in "${BASEPATH}/tests/"*.c
do
binary="${file%.c}"
basename=$(basename ${binary})
${CC} -o "${binary}" "${file}" 1>&2
if [ $? -eq 0 ]; then
STDOUT=$(${binary})
if [ "${STDOUT}" != "" ]; then
echo "#define ${basename} ${STDOUT}"
else
echo "#define ${basename}"
fi
rm -f "${binary}"
fi
done
echo
echo "#endif"

View file

@ -0,0 +1,10 @@
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
(void)fork;
return 0;
}

View file

@ -0,0 +1,7 @@
#include <malloc.h>
int
main()
{
malloc_trim(0);
}

View file

@ -0,0 +1,14 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int
main(int argc,
char *argv[])
{
struct stat st;
(void)st.st_atim;
return 0;
}

View file

@ -0,0 +1,11 @@
#include <fcntl.h>
#include <sys/stat.h>
int
main(int argc,
char *argv[])
{
(void)utimensat;
return 0;
}

View file

@ -0,0 +1,4 @@
#pragma once
#define STATIC_ASSERT(condition) \
((void)sizeof(char[1 - 2*!(condition)]))

784
libfuse/include/fuse.h Normal file
View file

@ -0,0 +1,784 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#ifndef _FUSE_H_
#define _FUSE_H_
#include "extern_c.h"
#include "fuse_common.h"
#include <fcntl.h>
#include <time.h>
#include <utime.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/uio.h>
EXTERN_C_BEGIN
/* ----------------------------------------------------------- *
* Basic FUSE API *
* ----------------------------------------------------------- */
/** Handle for a FUSE filesystem */
struct fuse;
/** Structure containing a raw command */
struct fuse_cmd;
struct fuse_dirents_t;
typedef struct fuse_dirents_t fuse_dirents_t;
/**
* The file system operations:
*
* Most of these should work very similarly to the well known UNIX
* file system operations. A major exception is that instead of
* returning an error in 'errno', the operation should return the
* negated error value (-errno) directly.
*
* All methods are optional, but some are essential for a useful
* filesystem (e.g. getattr). Open, flush, release, fsync, opendir,
* releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock,
* init and destroy are special purpose methods, without which a full
* featured filesystem can still be implemented.
*
* Almost all operations take a path which can be of any length.
*
* Changed in fuse 2.8.0 (regardless of API version)
* Previously, paths were limited to a length of PATH_MAX.
*
* See http://fuse.sourceforge.net/wiki/ for more information. There
* is also a snapshot of the relevant wiki pages in the doc/ folder.
*/
struct fuse_operations
{
/** Get file attributes.
*
* Similar to stat(). The 'st_dev' and 'st_blksize' fields are
* ignored. The 'st_ino' field is ignored except if the 'use_ino'
* mount option is given.
*/
int (*getattr) (const char *, struct stat *, fuse_timeouts_t *);
/** Read the target of a symbolic link
*
* The buffer should be filled with a null terminated string. The
* buffer size argument includes the space for the terminating
* null character. If the linkname is too long to fit in the
* buffer, it should be truncated. The return value should be 0
* for success.
*/
int (*readlink) (const char *, char *, size_t);
/** Create a file node
*
* This is called for creation of all non-directory, non-symlink
* nodes. If the filesystem defines a create() method, then for
* regular files that will be called instead.
*/
int (*mknod) (const char *, mode_t, dev_t);
/** Create a directory
*
* Note that the mode argument may not have the type specification
* bits set, i.e. S_ISDIR(mode) can be false. To obtain the
* correct directory type bits use mode|S_IFDIR
* */
int (*mkdir) (const char *, mode_t);
/** Hide files unlinked / renamed over
*
* Allows storing of a file handle when a file is unlinked
* while open. Helps manage the fact the kernel usually does
* not send fh with getattr requests.
*/
int (*prepare_hide)(const char *name_, uint64_t *fh_);
int (*free_hide)(const uint64_t fh_);
/** Remove a file */
int (*unlink) (const char *);
/** Remove a directory */
int (*rmdir) (const char *);
/** Create a symbolic link */
int (*symlink) (const char *, const char *, struct stat *, fuse_timeouts_t *);
/** Rename a file */
int (*rename) (const char *, const char *);
/** Create a hard link to a file */
int (*link) (const char *, const char *, struct stat *, fuse_timeouts_t *);
/** Change the permission bits of a file */
int (*chmod) (const char *, mode_t);
int (*fchmod)(const fuse_file_info_t *, const mode_t);
/** Change the owner and group of a file */
int (*chown) (const char *, uid_t, gid_t);
int (*fchown)(const fuse_file_info_t *, const uid_t, const gid_t);
/** Change the size of a file */
int (*truncate) (const char *, off_t);
/** File open operation
*
* No creation (O_CREAT, O_EXCL) and by default also no
* truncation (O_TRUNC) flags will be passed to open(). If an
* application specifies O_TRUNC, fuse first calls truncate()
* and then open(). Only if 'atomic_o_trunc' has been
* specified and kernel version is 2.6.24 or later, O_TRUNC is
* passed on to open.
*
* Unless the 'default_permissions' mount option is given,
* open should check if the operation is permitted for the
* given flags. Optionally open may also return an arbitrary
* filehandle in the fuse_file_info structure, which will be
* passed to all file operations.
*
* Changed in version 2.2
*/
int (*open) (const char *, fuse_file_info_t *);
/** Get file system statistics
*
* The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
*
* Replaced 'struct statfs' parameter with 'struct statvfs' in
* version 2.5
*/
int (*statfs) (const char *, struct statvfs *);
/** Possibly flush cached data
*
* BIG NOTE: This is not equivalent to fsync(). It's not a
* request to sync dirty data.
*
* Flush is called on each close() of a file descriptor. So if a
* filesystem wants to return write errors in close() and the file
* has cached dirty data, this is a good place to write back data
* and return any errors. Since many applications ignore close()
* errors this is not always useful.
*
* NOTE: The flush() method may be called more than once for each
* open(). This happens if more than one file descriptor refers
* to an opened file due to dup(), dup2() or fork() calls. It is
* not possible to determine if a flush is final, so each flush
* should be treated equally. Multiple write-flush sequences are
* relatively rare, so this shouldn't be a problem.
*
* Filesystems shouldn't assume that flush will always be called
* after some writes, or that if will be called at all.
*
* Changed in version 2.2
*/
int (*flush) (const fuse_file_info_t *);
/** Release an open file
*
* Release is called when there are no more references to an open
* file: all file descriptors are closed and all memory mappings
* are unmapped.
*
* For every open() call there will be exactly one release() call
* with the same flags and file descriptor. It is possible to
* have a file opened more than once, in which case only the last
* release will mean, that no more reads/writes will happen on the
* file. The return value of release is ignored.
*
* Changed in version 2.2
*/
int (*release) (const fuse_file_info_t *);
/** Synchronize file contents
*
* If the datasync parameter is non-zero, then only the user data
* should be flushed, not the meta data.
*
* Changed in version 2.2
*/
int (*fsync) (const fuse_file_info_t *, int);
/** Set extended attributes */
int (*setxattr) (const char *, const char *, const char *, size_t, int);
/** Get extended attributes */
int (*getxattr) (const char *, const char *, char *, size_t);
/** List extended attributes */
int (*listxattr) (const char *, char *, size_t);
/** Remove extended attributes */
int (*removexattr) (const char *, const char *);
/** Open directory
*
* Unless the 'default_permissions' mount option is given,
* this method should check if opendir is permitted for this
* directory. Optionally opendir may also return an arbitrary
* filehandle in the fuse_file_info structure, which will be
* passed to readdir, closedir and fsyncdir.
*
* Introduced in version 2.3
*/
int (*opendir) (const char *,
fuse_file_info_t *);
/** Read directory
*
* This supersedes the old getdir() interface. New applications
* should use this.
*
* The filesystem may choose between two modes of operation:
*
* 1) The readdir implementation ignores the offset parameter, and
* passes zero to the filler function's offset. The filler
* function will not return '1' (unless an error happens), so the
* whole directory is read in a single readdir operation. This
* works just like the old getdir() method.
*
* 2) The readdir implementation keeps track of the offsets of the
* directory entries. It uses the offset parameter and always
* passes non-zero offset to the filler function. When the buffer
* is full (or an error happens) the filler function will return
* '1'.
*
* Introduced in version 2.3
*/
int (*readdir)(const fuse_file_info_t *,
fuse_dirents_t *);
int (*readdir_plus)(const fuse_file_info_t *,
fuse_dirents_t *);
/** Release directory
*
* Introduced in version 2.3
*/
int (*releasedir) (const fuse_file_info_t *);
/** Synchronize directory contents
*
* If the datasync parameter is non-zero, then only the user data
* should be flushed, not the meta data
*
* Introduced in version 2.3
*/
int (*fsyncdir) (const fuse_file_info_t *, int);
/**
* Initialize filesystem
*
* The return value will passed in the private_data field of
* fuse_context to all file operations and as a parameter to the
* destroy() method.
*
* Introduced in version 2.3
* Changed in version 2.6
*/
void *(*init) (struct fuse_conn_info *conn);
/**
* Clean up filesystem
*
* Called on filesystem exit.
*
* Introduced in version 2.3
*/
void (*destroy) (void);
/**
* Check file access permissions
*
* This will be called for the access() system call. If the
* 'default_permissions' mount option is given, this method is not
* called.
*
* This method is not called under Linux kernel versions 2.4.x
*
* Introduced in version 2.5
*/
int (*access) (const char *, int);
/**
* Create and open a file
*
* If the file does not exist, first create it with the specified
* mode, and then open it.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the mknod() and open() methods
* will be called instead.
*
* Introduced in version 2.5
*/
int (*create) (const char *, mode_t, fuse_file_info_t *);
/**
* Change the size of an open file
*
* This method is called instead of the truncate() method if the
* truncation was invoked from an ftruncate() system call.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the truncate() method will be
* called instead.
*
* Introduced in version 2.5
*/
int (*ftruncate) (const fuse_file_info_t *, off_t);
/**
* Get attributes from an open file
*
* This method is called instead of the getattr() method if the
* file information is available.
*
* Currently this is only called after the create() method if that
* is implemented (see above). Later it may be called for
* invocations of fstat() too.
*
* Introduced in version 2.5
*/
int (*fgetattr) (const fuse_file_info_t *, struct stat *, fuse_timeouts_t *);
/**
* Perform POSIX file locking operation
*
* The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
*
* For the meaning of fields in 'struct flock' see the man page
* for fcntl(2). The l_whence field will always be set to
* SEEK_SET.
*
* For checking lock ownership, the 'fuse_file_info->owner'
* argument must be used.
*
* For F_GETLK operation, the library will first check currently
* held locks, and if a conflicting lock is found it will return
* information without calling this method. This ensures, that
* for local locks the l_pid field is correctly filled in. The
* results may not be accurate in case of race conditions and in
* the presence of hard links, but it's unlikely that an
* application would rely on accurate GETLK results in these
* cases. If a conflicting lock is not found, this method will be
* called, and the filesystem may fill out l_pid by a meaningful
* value, or it may leave this field zero.
*
* For F_SETLK and F_SETLKW the l_pid field will be set to the pid
* of the process performing the locking operation.
*
* Note: if this method is not implemented, the kernel will still
* allow file locking to work locally. Hence it is only
* interesting for network filesystems and similar.
*
* Introduced in version 2.6
*/
int (*lock) (const fuse_file_info_t *,
int cmd,
struct flock *);
/**
* Change the access and modification times of a file with
* nanosecond resolution
*
* This supersedes the old utime() interface. New applications
* should use this.
*
* See the utimensat(2) man page for details.
*
* Introduced in version 2.6
*/
int (*utimens)(const char *, const struct timespec tv[2]);
int (*futimens)(const fuse_file_info_t *ffi_, const struct timespec tv_[2]);
/**
* Map block index within file to block index within device
*
* Note: This makes sense only for block device backed filesystems
* mounted with the 'blkdev' option
*
* Introduced in version 2.6
*/
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
/**
* Ioctl
*
* flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
* 64bit environment. The size and direction of data is
* determined by _IOC_*() decoding of cmd. For _IOC_NONE,
* data will be NULL, for _IOC_WRITE data is out area, for
* _IOC_READ in area and if both are set in/out area. In all
* non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
*
* If flags has FUSE_IOCTL_DIR then the fuse_file_info refers to a
* directory file handle.
*
* Introduced in version 2.8
*/
int (*ioctl) (const fuse_file_info_t *ffi,
unsigned long cmd,
void *arg,
unsigned int flags,
void *data,
uint32_t *out_bufsz);
/**
* Poll for IO readiness events
*
* Note: If ph is non-NULL, the client should notify
* when IO readiness events occur by calling
* fuse_notify_poll() with the specified ph.
*
* Regardless of the number of times poll with a non-NULL ph
* is received, single notification is enough to clear all.
* Notifying more times incurs overhead but doesn't harm
* correctness.
*
* The callee is responsible for destroying ph with
* fuse_pollhandle_destroy() when no longer in use.
*
* Introduced in version 2.8
*/
int (*poll) (const fuse_file_info_t *ffi,
fuse_pollhandle_t *ph,
unsigned *reventsp);
/** Write contents of buffer to an open file
*
* Similar to the write() method, but data is supplied in a
* generic buffer. Use fuse_buf_copy() to transfer data to
* the destination.
*
* Introduced in version 2.9
*/
int (*write) (const fuse_file_info_t *ffi,
const char *data,
size_t size,
off_t off);
/** Store data from an open file in a buffer
*
* Similar to the read() method, but data is stored and
* returned in a generic buffer.
*
* No actual copying of data has to take place, the source
* file descriptor may simply be stored in the buffer for
* later data transfer.
*
* The buffer must be allocated dynamically and stored at the
* location pointed to by bufp. If the buffer contains memory
* regions, they too must be allocated using malloc(). The
* allocated memory will be freed by the caller.
*
* Introduced in version 2.9
*/
int (*read)(const fuse_file_info_t *ffi,
char *buf,
size_t size,
off_t off);
/**
* Perform BSD file locking operation
*
* The op argument will be either LOCK_SH, LOCK_EX or LOCK_UN
*
* Nonblocking requests will be indicated by ORing LOCK_NB to
* the above operations
*
* For more information see the flock(2) manual page.
*
* Additionally fi->owner will be set to a value unique to
* this open file. This same value will be supplied to
* ->release() when the file is released.
*
* Note: if this method is not implemented, the kernel will still
* allow file locking to work locally. Hence it is only
* interesting for network filesystems and similar.
*
* Introduced in version 2.9
*/
int (*flock) (const fuse_file_info_t *, int op);
/**
* Allocates space for an open file
*
* This function ensures that required space is allocated for specified
* file. If this function returns success then any subsequent write
* request to specified range is guaranteed not to fail because of lack
* of space on the file system media.
*
* Introduced in version 2.9.1
*/
int (*fallocate) (const fuse_file_info_t *, int, off_t, off_t);
/**
* Copy a range of data from one file to another
*
* Performs an optimized copy between two file descriptors without
* the additional cost of transferring data through the FUSE kernel
* module to user space (glibc) and then back into the FUSE filesystem
* again.
*
* In case this method is not implemented, glibc falls back to
* reading data from the source and writing to the
* destination. Effectively doing an inefficient copy of the
* data.
*/
ssize_t (*copy_file_range)(const fuse_file_info_t *fi_in,
off_t offset_in,
const fuse_file_info_t *fi_out,
off_t offset_out,
size_t size,
int flags);
ssize_t (*setupmapping)(uint64_t *fh_,
uint64_t foffset_,
uint64_t len_,
uint64_t flags_,
uint64_t moffset_);
int (*removemapping)();
int (*syncfs)();
int (*tmpfile)(const char *, mode_t, fuse_file_info_t *);
};
/** Extra context that may be needed by some filesystems
*
* The uid, gid and pid fields are not filled in case of a writepage
* operation.
*/
struct fuse_context
{
/** Pointer to the fuse object */
struct fuse *fuse;
/** User ID of the calling process */
uid_t uid;
/** Group ID of the calling process */
gid_t gid;
/** Thread ID of the calling process */
pid_t pid;
/** Umask of the calling process (introduced in version 2.8) */
mode_t umask;
};
/**
* Main function of FUSE.
*
* This is for the lazy. This is all that has to be called from the
* main() function.
*
* This function does the following:
* - parses command line options (-d -s and -h)
* - passes relevant mount options to the fuse_mount()
* - installs signal handlers for INT, HUP, TERM and PIPE
* - registers an exit handler to unmount the filesystem on program exit
* - creates a fuse handle
* - registers the operations
* - calls either the single-threaded or the multi-threaded event loop
*
* Note: this is currently implemented as a macro.
*
* @param argc the argument counter passed to the main() function
* @param argv the argument vector passed to the main() function
* @param op the file system operation
* @return 0 on success, nonzero on failure
*/
/*
int fuse_main(int argc, char *argv[], const struct fuse_operations *op);
*/
#define fuse_main(argc, argv, op) \
fuse_main_real(argc, argv, op, sizeof(*(op)))
/* ----------------------------------------------------------- *
* More detailed API *
* ----------------------------------------------------------- */
/**
* Create a new FUSE filesystem.
*
* @param ch the communication channel
* @param args argument vector
* @param op the filesystem operations
* @param op_size the size of the fuse_operations structure
* @return the created FUSE handle
*/
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op, size_t op_size);
/**
* Destroy the FUSE handle.
*
* The communication channel attached to the handle is also destroyed.
*
* NOTE: This function does not unmount the filesystem. If this is
* needed, call fuse_unmount() before calling this function.
*
* @param f the FUSE handle
*/
void fuse_destroy(struct fuse *f);
/**
* Exit from event loop
*
* @param f the FUSE handle
*/
void fuse_exit(struct fuse *f);
int fuse_config_read_thread_count(const struct fuse *f);
int fuse_config_process_thread_count(const struct fuse *f);
int fuse_config_process_thread_queue_depth(const struct fuse *f);
const char* fuse_config_pin_threads(const struct fuse *f);
/**
* FUSE event loop with multiple threads
*
* Requests from the kernel are processed, and the appropriate
* operations are called. Request are processed in parallel by
* distributing them between multiple threads.
*
* Calling this function requires the pthreads library to be linked to
* the application.
*
* @param f the FUSE handle
* @return 0 if no error occurred, -1 otherwise
*/
int fuse_loop_mt(struct fuse *f);
/**
* Get the current context
*
* The context is only valid for the duration of a filesystem
* operation, and thus must not be stored and used later.
*
* @return the context
*/
struct fuse_context *fuse_get_context(void);
/**
* Check if the current request has already been interrupted
*
* @return 1 if the request has been interrupted, 0 otherwise
*/
int fuse_interrupted(void);
/**
* Obsolete, doesn't do anything
*
* @return -EINVAL
*/
int fuse_invalidate(struct fuse *f, const char *path);
/* Deprecated, don't use */
int fuse_is_lib_option(const char *opt);
/**
* The real main function
*
* Do not call this directly, use fuse_main()
*/
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size);
int fuse_start_maintenance_thread(struct fuse *fuse);
void fuse_stop_maintenance_thread(struct fuse *fuse);
int fuse_log_metrics_get(void);
void fuse_log_metrics_set(int enabled);
/**
* Iterate over cache removing stale entries
* use in conjunction with "-oremember"
*
* NOTE: This is already done for the standard sessions
*
* @param fuse struct fuse pointer for fuse instance
* @return the number of seconds until the next cleanup
*/
int fuse_clean_cache(struct fuse *fuse);
/*
* Stacking API
*/
/**
* Fuse filesystem object
*
* This is opaque object represents a filesystem layer
*/
struct fuse_fs;
/*
* These functions call the relevant filesystem operation, and return
* the result.
*
* If the operation is not defined, they return -ENOSYS, with the
* exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
* fuse_fs_releasedir and fuse_fs_statfs, which return 0.
*/
int fuse_notify_poll(fuse_pollhandle_t *ph);
/**
* Create a new fuse filesystem object
*
* This is usually called from the factory of a fuse module to create
* a new instance of a filesystem.
*
* @param op the filesystem operations
* @param op_size the size of the fuse_operations structure
* @return a new filesystem object
*/
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size);
/* ----------------------------------------------------------- *
* Advanced API for event handling, don't worry about this... *
* ----------------------------------------------------------- */
/* NOTE: the following functions are deprecated, and will be removed
from the 3.0 API. Use the lowlevel session functions instead */
/** Function type used to process commands */
typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *);
/** This is the part of fuse_main() before the event loop */
struct fuse *fuse_setup(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
char **mountpoint);
/** This is the part of fuse_main() after the event loop */
void fuse_teardown(struct fuse *fuse, char *mountpoint);
/** Multi threaded event loop, which calls the custom command
processor function */
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data);
/** Return the exited flag, which indicates if fuse_exit() has been
called */
int fuse_exited(struct fuse *f);
/** This function is obsolete and implemented as a no-op */
void fuse_set_getcontext_func(struct fuse_context *(*func)(void));
/** Get session from fuse object */
struct fuse_session *fuse_get_session(struct fuse *f);
void fuse_gc1();
void fuse_gc();
void fuse_invalidate_all_nodes();
EXTERN_C_END
#endif /* _FUSE_H_ */

View file

@ -1,20 +1,43 @@
#pragma once
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/** @file */
#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_)
#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h> instead."
#endif
#ifndef _FUSE_COMMON_H_
#define _FUSE_COMMON_H_
#include "extern_c.h"
#include "fuse_conn_info.hpp"
#include "fuse_opt.h"
#include "fuse_timeouts.h"
#include <stdint.h>
#include <sys/types.h>
/** Major version of FUSE library interface */
#define FUSE_MAJOR_VERSION 2
/** Minor version of FUSE library interface */
#define FUSE_MINOR_VERSION 9
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
/* This interface uses 64 bit off_t */
#if _FILE_OFFSET_BITS != 64
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
#endif
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
#define FUSE_DEFAULT_MAX_MAX_PAGES 256
#define FUSE_MAX_MAX_PAGES 256
EXTERN_C_BEGIN
@ -64,20 +87,17 @@ struct fuse_file_info_t
uint32_t parallel_direct_writes:1;
uint32_t noflush:1;
uint32_t passthrough:1;
/** File handle. May be filled in by filesystem in open().
Available in all other file operations */
uint64_t fh;
int32_t backing_id;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
};
/**
* Capability bits for 'fuse_conn_info_t.capable' and 'fuse_conn_info_t.want'
* Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
*
* FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
* FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
@ -88,29 +108,23 @@ struct fuse_file_info_t
* FUSE_CAP_IOCTL_DIR: ioctl support on directories
* FUSE_CAP_CACHE_SYMLINKS: cache READLINK responses
*/
#define FUSE_CAP_ASYNC_READ (1ULL << 0)
#define FUSE_CAP_POSIX_LOCKS (1ULL << 1)
#define FUSE_CAP_ATOMIC_O_TRUNC (1ULL << 3)
#define FUSE_CAP_EXPORT_SUPPORT (1ULL << 4)
#define FUSE_CAP_BIG_WRITES (1ULL << 5)
#define FUSE_CAP_DONT_MASK (1ULL << 6)
#define FUSE_CAP_FLOCK_LOCKS (1ULL << 10)
#define FUSE_CAP_IOCTL_DIR (1ULL << 11)
#define FUSE_CAP_READDIR_PLUS (1ULL << 13)
#define FUSE_CAP_READDIR_PLUS_AUTO (1ULL << 14)
#define FUSE_CAP_ASYNC_DIO (1ULL << 15)
#define FUSE_CAP_WRITEBACK_CACHE (1ULL << 16)
#define FUSE_CAP_PARALLEL_DIROPS (1ULL << 18)
#define FUSE_CAP_POSIX_ACL (1ULL << 19)
#define FUSE_CAP_CACHE_SYMLINKS (1ULL << 20)
#define FUSE_CAP_MAX_PAGES (1ULL << 21)
#define FUSE_CAP_SETXATTR_EXT (1ULL << 22)
#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP (1ULL << 23)
#define FUSE_CAP_CREATE_SUPP_GROUP (1ULL << 24)
#define FUSE_CAP_PASSTHROUGH (1ULL << 25)
#define FUSE_CAP_HANDLE_KILLPRIV (1ULL << 26)
#define FUSE_CAP_HANDLE_KILLPRIV_V2 (1ULL << 27)
#define FUSE_CAP_ALLOW_IDMAP (1ULL << 28)
#define FUSE_CAP_ASYNC_READ (1 << 0)
#define FUSE_CAP_POSIX_LOCKS (1 << 1)
#define FUSE_CAP_ATOMIC_O_TRUNC (1 << 3)
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
#define FUSE_CAP_IOCTL_DIR (1 << 11)
#define FUSE_CAP_READDIR_PLUS (1 << 13)
#define FUSE_CAP_READDIR_PLUS_AUTO (1 << 14)
#define FUSE_CAP_ASYNC_DIO (1 << 15)
#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
#define FUSE_CAP_POSIX_ACL (1 << 19)
#define FUSE_CAP_CACHE_SYMLINKS (1 << 20)
#define FUSE_CAP_MAX_PAGES (1 << 21)
#define FUSE_CAP_SETXATTR_EXT (1 << 22)
/**
* Ioctl flags
@ -129,30 +143,90 @@ struct fuse_file_info_t
#define FUSE_IOCTL_MAX_IOV 256
/**
* Connection information, passed to the ->init() method
*
* Some of the elements are read-write, these can be changed to
* indicate the value requested by the filesystem. The requested
* value must usually be smaller than the indicated value.
*/
struct fuse_conn_info {
/**
* Major version of the protocol (read-only)
*/
unsigned proto_major;
/**
* Minor version of the protocol (read-only)
*/
unsigned proto_minor;
/**
* Maximum size of the write buffer
*/
unsigned max_write;
/**
* Maximum readahead
*/
unsigned max_readahead;
/**
* Capability flags, that the kernel supports
*/
unsigned capable;
/**
* Capability flags, that the filesystem wants to enable
*/
unsigned want;
/**
* Maximum number of backgrounded requests
*/
unsigned max_background;
/**
* Kernel congestion threshold parameter
*/
unsigned congestion_threshold;
/**
* Max pages
*/
uint16_t max_pages;
/**
* For future use.
*/
unsigned reserved[22];
};
struct fuse_session;
struct fuse_chan;
struct fuse_pollhandle_t;
typedef struct fuse_pollhandle_t fuse_pollhandle_t;
/**
* Mount a FUSE filesystem.
* Create a FUSE mountpoint
*
* This function creates a FUSE mount and returns the /dev/fuse file descriptor.
* The file descriptor is stored in the session for internal use.
* Returns a control file descriptor suitable for passing to
* fuse_new()
*
* @param mountpoint the mount point path
* @param args argument vector
* @return the /dev/fuse file descriptor on success, -1 on failure
* @return the communication channel on success, NULL on failure
*/
int fuse_mount(const char *mountpoint, struct fuse_args *args);
struct fuse_chan *fuse_mount(const char *mountpoint,
struct fuse_args *args);
/**
* Umount a FUSE mountpoint
*
* @param mountpoint the mount point path
* @param fd the /dev/fuse file descriptor (or -1 if already closed)
* @param ch the communication channel
*/
void fuse_unmount(const char *mountpoint, int fd);
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
/**
* Parse common options
@ -315,6 +389,70 @@ struct fuse_buf {
off_t pos;
};
/**
* Data buffer vector
*
* An array of data buffers, each containing a memory pointer or a
* file descriptor.
*
* Allocate dynamically to add more than one buffer.
*/
struct fuse_bufvec {
/**
* Number of buffers in the array
*/
size_t count;
/**
* Index of current buffer within the array
*/
size_t idx;
/**
* Current offset within the current buffer
*/
size_t off;
/**
* Array of buffers
*/
struct fuse_buf buf[1];
};
/* Initialize bufvec with a single buffer of given size */
#define FUSE_BUFVEC_INIT(size__) \
((struct fuse_bufvec) { \
/* .count= */ 1, \
/* .idx = */ 0, \
/* .off = */ 0, \
/* .buf = */ { /* [0] = */ { \
/* .size = */ (size__), \
/* .flags = */ (enum fuse_buf_flags) 0, \
/* .mem = */ NULL, \
/* .fd = */ -1, \
/* .pos = */ 0, \
} } \
} )
/**
* Get total size of data in a fuse buffer vector
*
* @param bufv buffer vector
* @return size of data
*/
size_t fuse_buf_size(const struct fuse_bufvec *bufv);
/**
* Copy data from one buffer vector to another
*
* @param dst destination buffer vector
* @param src source buffer vector
* @param flags flags controlling the copy
* @return actual number of bytes copied or -errno on error
*/
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
enum fuse_buf_copy_flags flags);
/* ----------------------------------------------------------- *
* Signal handling *
* ----------------------------------------------------------- */
@ -341,3 +479,5 @@ int fuse_set_signal_handlers(struct fuse_session *se);
void fuse_remove_signal_handlers(struct fuse_session *se);
EXTERN_C_END
#endif /* _FUSE_COMMON_H_ */

View file

@ -1,7 +1,7 @@
/*
ISC License
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@ -16,32 +16,16 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config_log_file.hpp"
#pragma once
#include "debug.hpp"
#include "fuse_cfg.hpp"
#include <memory>
#include <string>
LogFile::LogFile(const std::string &s_)
{
if(!s_.empty())
fuse_debug_set_output(s_);
}
int fuse_config_get_read_thread_count();
int fuse_config_get_process_thread_count();
int fuse_config_get_process_thread_queue_depth();
std::string fuse_config_get_pin_threads();
std::string
LogFile::to_string(void) const
{
auto filepath = fuse_cfg.log_filepath();
return (filepath ? *filepath : "");
}
int
LogFile::from_string(const std::string_view s_)
{
const std::string s{s_};
return fuse_debug_set_output(s);
}
void fuse_config_set_read_thread_count(int const);
void fuse_config_set_process_thread_count(int const);
void fuse_config_set_process_thread_queue_depth(int const);
void fuse_config_set_pin_threads(std::string const);

Some files were not shown because too many files have changed in this diff Show more