2
3
Fork
You've already forked nextcloud-fuse
0
FUSE-based virtual filesystem for Nextcloud on Linux
  • Rust 99.4%
  • Makefile 0.6%
Troed Sångberg 823c0ccf96 test: git clone reads real content with fsck verification
Seed the source bare repo with one commit containing a small file so
the clone exercises the full writeback-cache + upload pipeline (pack-data
transfer, block_cache reads/writes). Verify content on disk and run
git fsck to catch any pack corruption.
2026年07月12日 18:38:22 +02:00
docs Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
src Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
tests test: git clone reads real content with fsck verification 2026年07月12日 18:38:22 +02:00
vendor/fuse3 Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
.gitignore Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
Cargo.toml Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
FUSE3_PR.md Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
FUSE_RACE_CONDITION.md Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
LICENSE First public push to enable wider testing 2026年06月22日 23:01:36 +02:00
Makefile Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
README.md Squash devel onto main: full fix stack for git clone reliability 2026年07月12日 18:31:05 +02:00
testmount.sh First public push to enable wider testing 2026年06月22日 23:01:36 +02:00

IMPORTANT CAVEAT

BETA RELEASE - FOR TESTING PURPOSES

This version is made public for beta testing. There's a thorough test suite that tries to cover all data loss scenarios but it's too early to claim that none might exit. This is still pre-release software.

What this means:

  • Core FUSE operations work correctly
  • Data loss bugs identified in testing have been fixed
  • 307 tests pass, including data loss regression tests
  • ⚠️ Not yet tested extensively in real-world scenarios
  • ⚠️ Performance optimizations still in progress
  • ⚠️ Desktop client integration not implemented
  • ⚠️ No offline mode support

Please test on non-critical data and report issues. Do not use as your primary file access method until a stable release is announced. Or, if you do, have backups handy.

The name of this project describes its functionality: "Nextcloud FUSE". The project is in no way endorsed by or otherwise associated with Nextcloud GmbH. Nextcloud trademarks are used strictly to describe the project. If Nextcloud, when the project reaches suitable maturity, decide that they would like to host the project the author will happily hand it over.

With all that said - here's some README content:

Nextcloud FUSE

FUSE-based virtual filesystem for Nextcloud on Linux.

Overview

This project provides a true virtual filesystem for Nextcloud on Linux using FUSE (Filesystem in Userspace). It enables on-demand access to Nextcloud files without requiring a full sync, with intelligent local caching for performance.

Status

Beta release - Core functionality complete and tested. Suitable for testing with non-critical data. All identified data loss bugs have been fixed. See the test suite for details on what's been verified.

Features

  • On-demand file access (download only when accessed)
  • Block-level caching (4MB blocks by default)
  • Write-back caching with async upload
  • Core FUSE operations (getattr, readdir, open, read, write, create, mkdir, unlink, rmdir, rename)
  • Metadata cache with TTL
  • Upload manager with retry logic and conflict detection
  • Advanced FUSE operations (truncate, chmod, utimens via setattr)
  • SIGTERM handling and graceful shutdown with fusermount3 unmount
  • SQLite WAL mode for concurrent access
  • Native chunked upload protocol (per-block uploads via MKCOL + PUT + MOVE assembly)
  • Parallel block downloads with semaphore-bounded concurrency
  • Read-ahead prefetch on cache miss
  • SQLite persistence for upload session resume
  • Comprehensive test suite (307 tests)
  • symlink/readlink/xattr (return ENOSYS — correct for cloud storage)
  • Desktop client integration (IPC not implemented)
  • Pin states support
  • Offline mode

Architecture

User Applications → Linux Kernel (FUSE) → nextcloudfs (Rust) → Nextcloud Server
 ↓
 Cache (Block + Metadata)

Building

Prerequisites

Runtime Dependencies

  • libfuse3 >= 3.0

  • FUSE configuration: uncomment user_allow_other in /etc/fuse.conf

    The filesystem mounts with allow_other so that applications running under different user IDs (file managers, browsers, etc.) can access the mounted files. Without this, the FUSE kernel module rejects the mount unless user_allow_other is enabled in /etc/fuse.conf:

    sudo sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf
    

Build Dependencies

  • Rust >= 1.70
  • Cargo >= 1.70

Build

# Clone the repository
git clone https://codeberg.org/troed/nextcloud-fuse.git
cd nextcloud-fuse
# Build in debug mode
cargo build
# Build in release mode
cargo build --release
# Install locally
cargo install --path .

The binary will be at target/release/nextcloudfs.

Usage

Standalone Mode

# Mount a Nextcloud folder
./target/release/nextcloudfs \
 --server http://localhost:8888 \
 --username testuser \
 --password MySecurePassword456! \
 --remote-path /fuse-test/ \
 /mnt/nextcloud
# Unmount
fusermount3 -u /mnt/nextcloud

Configuration

Configuration supports three mechanisms with the following precedence (highest to lowest):

  1. CLI arguments (with environment variable fallback via clap)
  2. TOML configuration file (~/.config/nextcloud-fuse/config.toml or custom path)
  3. Built-in defaults

CLI Arguments

All CLI arguments support environment variable fallback using the NEXTCLOUD_FUSE_* prefix:

# Server and authentication
--server URL # NEXTCLOUD_FUSE_SERVER
--username USER # NEXTCLOUD_FUSE_USERNAME
--password PASS # NEXTCLOUD_FUSE_PASSWORD
--token TOKEN # NEXTCLOUD_FUSE_TOKEN
# Mount configuration
--remote-path PATH # NEXTCLOUD_FUSE_REMOTE_PATH (default: /)
--mount-point PATH # Required, no env var fallback
# Configuration file
--config PATH # NEXTCLOUD_FUSE_CONFIG
# Logging
--log-level LEVEL # NEXTCLOUD_FUSE_LOG_LEVEL (default: info)
 # Options: trace, debug, info, warn, error
--log-format FORMAT # NEXTCLOUD_FUSE_LOG_FORMAT (default: text)
 # Options: text, json, compact
# Debugging
--verbose # Enable verbose output (no env var)
# IPC (Inter-Process Communication)
--no-ipc # NEXTCLOUD_FUSE_NO_IPC
--ipc-socket PATH # NEXTCLOUD_FUSE_IPC_SOCKET

Configuration File

Location: ~/.config/nextcloud-fuse/config.toml (or custom path via --config)

All fields are optional. Example:

# Server connection
server_url = "https://nextcloud.example.com"
username = "user"
password = "app-password"
# token = "bearer-token" # Alternative to password
remote_path = "/Documents"
# Cache settings
cache_dir = "/home/user/.cache/nextcloud-fuse"
cache_size = "10GB" # Supports: "10GB", "500MB", "100KB", or raw bytes
block_size = "4MB"
metadata_ttl = 30 # Seconds
# Performance
parallel_downloads = 4
prefetch = true
# Logging
log_level = "info"
log_format = "text"
debug = false
# IPC
no_ipc = false
# ipc_socket = "/tmp/nextcloud-fuse.sock"

Environment Variables

All environment variables use the NEXTCLOUD_FUSE_* prefix:

export NEXTCLOUD_FUSE_SERVER="https://nextcloud.example.com"
export NEXTCLOUD_FUSE_USERNAME="user"
export NEXTCLOUD_FUSE_PASSWORD="app-password"
export NEXTCLOUD_FUSE_REMOTE_PATH="/Documents"
export NEXTCLOUD_FUSE_LOG_LEVEL="debug"

Precedence Example

# Config file sets cache_size = "5GB"
# Environment variable sets NEXTCLOUD_FUSE_CACHE_SIZE="10GB"
# CLI argument sets --cache-size "20GB"
# Result: cache_size = "20GB" (CLI wins)

Note: Environment variables are handled by clap's env feature for CLI arguments, not separately. The NEXTCLOUD_FUSE_* env vars provide fallback values when CLI arguments are not provided.

Project Structure

nextcloud-fuse/
├── src/ # Rust source code
│ ├── main.rs # Entry point, CLI, mount lifecycle
│ ├── lib.rs # Library root
│ ├── config.rs # Configuration
│ ├── logging.rs # Logging
│ ├── error.rs # Error types
│ ├── fuse_operations.rs # FUSE operations
│ ├── upload.rs # Upload manager
│ ├── api/ # Nextcloud API client
│ │ ├── client.rs
│ │ ├── webdav.rs
│ │ ├── xml.rs
│ │ ├── error.rs
│ │ └── path.rs
│ ├── cache/ # Caching implementation
│ │ ├── block_cache.rs
│ │ └── metadata_cache.rs
│ └── utils/ # Utilities
│ ├── mod.rs
│ └── path.rs
├── tests/ # Test suite
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ ├── reliability/ # Reliability tests
│ ├── test_block_boundaries.rs # Block boundary crossing tests
│ └── test_concurrent_ops.rs # Concurrent FUSE operation tests
├── Cargo.toml # Rust dependencies
└── README.md # This file

Testing

Unit Tests (101 tests)

Unit tests cover configuration, errors, logging, utilities, metadata cache, block cache, API client, chunked upload sessions, and session SQLite persistence. They require no external services.

# Run all unit tests
cargo test --lib
# Run specific test
cargo test test_name

Component Tests (82 tests)

Auto-discovered test targets in tests/*.rs covering configuration parsing, error handling, file reading/writing logic, FUSE skeleton, logging, metadata cache, block boundary crossing, concurrent operations, and utilities. They require no external services.

# Run all component tests (no server required)
cargo test --test test_block_boundaries --test test_concurrent_ops --test test_config --test test_errors --test test_file_reading --test test_file_writing --test test_fuse_skeleton --test test_logging --test test_metadata_cache --test test_utils
# Or run a single test
cargo test --test test_block_boundaries

Integration Tests (22 tests)

Integration tests exercise FUSE mount/unmount lifecycle, file read/write, random-access I/O, crash recovery, and real-API interactions. They require a running Nextcloud instance (see Test Instance).

# Run all integration tests
make nc-start
cargo test --test integration

Reliability Tests (97 tests)

A comprehensive reliability test suite verifies data integrity under concurrent access, server crashes, and edge cases. All tests require a running Nextcloud instance (see Test Instance).

Test Groups:

Group Tests Description
harness 5 Unit tests for the test harness infrastructure
test_cache_behavior 15 Block cache insert/get, TTL expiration, multiple blocks, stats
test_cache_data_loss 4 SQLite blindness, block index/file offset mismatch, deadlock fixes
test_concurrent_ops 6 Concurrent reads, writes, directory creates, deletes, mixed operations
test_data_integrity 13 Edge cases: empty files, null bytes, unicode, special chars, binary, very long filenames
test_data_loss_scenarios 5 Upload failure state, cache restart, overwrite atomicity, rapid create/delete
test_directory_ops 10 Create, rename, move, rmdir, deep hierarchies, many files
test_file_ops 10 Create/read small/medium/large files, overwrite, delete, read exact bytes
test_mount_ops 10 Harness setup, getattr, readdir, cleanup, statfs, timestamps
test_server_crash 10 Crash during write/delete/rename/mkdir, multiple crashes, recovery verification
test_upload_pipeline 9 Full upload, chunked fallback, idempotency, multi-block, stats tracking

Execution Model:

Tests run in two phases to avoid interference:

  1. Phase 1 (parallel): All non-crash tests run concurrently with RUST_TEST_THREADS=4
  2. Phase 2 (sequential): Crash tests run single-threaded since they kill and restart the container
# Run all reliability tests (requires Nextcloud instance)
make test-reliability
# Run only non-crash tests (parallel)
RUST_TEST_THREADS=4 cargo test --test reliability -- test_cache_behavior test_cache_data_loss test_concurrent_ops test_data_integrity test_data_loss_scenarios test_directory_ops test_file_ops test_mount_ops test_upload_pipeline harness --include-ignored
# Run only crash tests (sequential)
RUST_TEST_THREADS=1 cargo test --test reliability -- test_server_crash --include-ignored
# Run a single test
make test-single TEST=test_concurrent_reads_same_file

Crash Test Mechanism:

The ServerCrashSimulator in the test harness (tests/reliability/harness.rs) uses podman kill + podman start to simulate server crashes. After each crash recovery, the harness re-applies a config override to ensure Nextcloud stays in "installed" state (the container image does not persist config changes). This override is written to /var/www/html/config/upgrade-disable-web.config.php via podman exec.

# Check test compilation
make test-check
# Start the test instance
make nc-start

Test Results (Current)

Unit tests (src/) 101 (no server required)
Component tests (no server): 77
 ├─ Config/Errors/Utils/Logging/Skeleton 34
 ├─ File reading 10
 ├─ File writing (writes, no API calls) 4
 ├─ Metadata cache 21
 ├─ Block boundary crossing 5
 └─ Concurrent operations 3
Component tests (require server): 5 (create/mkdir/rmdir)
Integration tests (tests/integration) 22 (require server)
Reliability tests (tests/reliability) 97 (require server)
Total (no server): 178
Total (with server): 302

Test Instance

A rootless Podman-based test instance is configured for safe testing:

  • Container: nextcloud-fuse-test
  • Port: 8888 (HTTP)
  • Test User: testuser / MySecurePassword456!
  • Admin User: admin / admin123
  • Test Path: /fuse-test/

Config Persistence: The container image regenerates config.php on each restart, removing the installed flag. To work around this, the test harness writes a config override to /var/www/html/config/upgrade-disable-web.config.php after each crash recovery. This file is loaded by Nextcloud's .config.php merging mechanism and provides the installed, secret, passwordsalt, instanceid, and database settings.

License

Creative Commons Zero - See LICENSE file.