Skip to content

Feature Request: Configurable inode calculation for rclone mount with 32-bit compatibility #8938

@Shkarlatov

Description

@Shkarlatov

Problem Description

When using rclone mount, some legacy 32-bit applications fail to work correctly with the mounted directories. This is because FUSE (and thus rclone) can generate very large inode numbers that exceed the 32-bit integer limit, which these older applications cannot handle.

Background

I tried various workarounds, including a function intercept library (inode64.so from inodes64.html). While it helps in some cases, it does not work for statically linked binaries.

The solution that ultimately worked for me was using mergerfs with its inodecalc=passthrough option:

mergerfs -o defaults,allow_other,inodecalc=passthrough /path1:/path1 /mount_point

Feature Request

I propose adding a --inode-calculation or --inodecalc option to rclone mount, similar to the excellent inodecalc mechanism in mergerfs (mergerfs inodecalc documentation).
Suggested Algorithms

Potential modes could include:

Standard algorithms:

  • passthrough - Use the underlying remote's inode number if available
  • path-hash - Generate inode from path hash
  • dev-id-hash - Incorporate device ID for uniqueness
  • hybrid - Mixed strategy for balance

and 32-bit compatible versions:

  • path-hash32 - 32-bit version of path-hash
  • dev-id-hash32 - 32-bit version of dev-id-hash
  • hybrid32 - 32-bit version of hybrid

Why 32-bit Variants Matter

The *32 variants are particularly important as they specifically address the 32-bit application compatibility issue by ensuring generated inode values never exceed 2^31-1 (or 2^32-1 for unsigned). This would greatly improve compatibility with legacy 32-bit applications without requiring external tools or LD_PRELOAD tricks.

Example and steps to reproduce

# stat.c   man stat (2) example
# 
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <time.h>
int
main(int argc, char *argv[])
{
    struct stat sb;
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if (lstat(argv[1], &sb) == -1) {
        perror("lstat");
        exit(EXIT_FAILURE);
    }
    printf("ID of containing device:  [%x,%x]\n",
           major(sb.st_dev),
           minor(sb.st_dev));
    printf("File type:                ");
    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK:  printf("block device\n");            break;
    case S_IFCHR:  printf("character device\n");        break;
    case S_IFDIR:  printf("directory\n");               break;
    case S_IFIFO:  printf("FIFO/pipe\n");               break;
    case S_IFLNK:  printf("symlink\n");                 break;
    case S_IFREG:  printf("regular file\n");            break;
    case S_IFSOCK: printf("socket\n");                  break;
    default:       printf("unknown?\n");                break;
    }
    printf("I-node number:            %ju\n", (uintmax_t) sb.st_ino);
    printf("Mode:                     %jo (octal)\n",
           (uintmax_t) sb.st_mode);
    printf("Link count:               %ju\n", (uintmax_t) sb.st_nlink);
    printf("Ownership:                UID=%ju   GID=%ju\n",
           (uintmax_t) sb.st_uid, (uintmax_t) sb.st_gid);
    printf("Preferred I/O block size: %jd bytes\n",
           (intmax_t) sb.st_blksize);
    printf("File size:                %jd bytes\n",
           (intmax_t) sb.st_size);
    printf("Blocks allocated:         %jd\n",
           (intmax_t) sb.st_blocks);
    printf("Last status change:       %s", ctime(&sb.st_ctime));
    printf("Last file access:         %s", ctime(&sb.st_atime));
    printf("Last file modification:   %s", ctime(&sb.st_mtime));
    exit(EXIT_SUCCESS);
}

Host ubuntu 24.04 amd64
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0

g++ -m32 stat.c -o stat32
g++ -m64 stat.c -o stat64

mkdir -p /rclone_mount
rclone mount /syscall /rclone_mount --vfs-cache-mode full --allow-other --daemon

echo '### call stat64 ###'
/syscall/stat/stat64 /rclone_mount/test
echo '### call stat32 ###'
/syscall/stat/stat32 /rclone_mount/test

mkdir -p /mergerfs_mount
mergerfs -o defaults,allow_other,inodecalc=passthrough /rclone_mount /mergerfs_mount
echo '### call stat64 on mergerfs ###'
/syscall/stat/stat64 /mergerfs_mount/test
echo '### call stat32 on mergerfs ###'
/syscall/stat/stat32 /mergerfs_mount/test



### call stat64 ###
ID of containing device:  [0,87]
File type:                regular file
I-node number:            14597221540505887712
Mode:                     100644 (octal)
Link count:               1
Ownership:                UID=0   GID=0
Preferred I/O block size: 4096 bytes
File size:                6 bytes
Blocks allocated:         1
Last status change:       Sun Nov  2 14:50:29 2025
Last file access:         Sun Nov  2 14:50:29 2025
Last file modification:   Sun Nov  2 14:50:29 2025

### call stat32 ###
lstat: Value too large for defined data type

### call stat64 on mergerfs ###
ID of containing device:  [0,88]
File type:                regular file
I-node number:            2
Mode:                     100644 (octal)
Link count:               1
Ownership:                UID=0   GID=0
Preferred I/O block size: 4096 bytes
File size:                6 bytes
Blocks allocated:         1
Last status change:       Sun Nov  2 14:50:29 2025
Last file access:         Sun Nov  2 14:50:29 2025
Last file modification:   Sun Nov  2 14:50:29 2025

### call stat32 on mergerfs ###
ID of containing device:  [0,88]
File type:                regular file
I-node number:            2
Mode:                     100644 (octal)
Link count:               1
Ownership:                UID=0   GID=0
Preferred I/O block size: 4096 bytes
File size:                6 bytes
Blocks allocated:         1
Last status change:       Sun Nov  2 14:50:29 2025
Last file access:         Sun Nov  2 14:50:29 2025
Last file modification:   Sun Nov  2 14:50:29 2025

This feature would make rclone mount even more versatile and robust for complex environments where legacy software is still in use.

Thank you for considering this feature.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions