www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - FUSE (Filesystem in Userspace) and OXFuse

I have been developing [my own 
wrapper](https://code.dlang.org/packages/oxfuse) around **libfuse 
v3** for more than 3 years. I originally needed it for [my 
semantic filesystem project](https://codeberg.org/os-18/vitis). 
Existing solutions such as **dfuse** and **fuse-d** were based on 
the deprecated **libfuse v2** and very limited functionally.

Using some ideas from **dfuse**, I developed a much more advanced 
wrapper around **libfuse** named **OXFuse** (Object-oriented 
eXtension for FUSE) To create a filesystem, you inherit from the 
`FileSystem` class and override the required methods representing 
file operations. Developing a filesystem with **OXFuse** requires 
solid Linux systems programming knowledge. To get started, you 
can look at the code in the `examples/` directory at the root of 
the project.



Unfortunately for the FS development community, libfuse has 
broken backward binary compatibility multiple times by adding new 
fields to some structures and/or changing their location 
(althrough it seems this should no longer happen). Because of 
this, I had to introduce multiple versions of the 
`fuse_file_info` and `fuse_config` structures inside OXFuse.

During compilation, the current libfuse version is detected 
automatically, and the correct structure versions are selected 
for the final build. Developers are not expected to use these 
structures directly - **OXFuse** provides the `FileInfo` and 
`FuseConfig` classes as abstractions instead.



One of the fundamental design decisions I made very early on was 
to use `string` in filesystem operation signatures. For example:

```d
void rename(string src, string dst, uint flags);
```

I know that in similar cases it is customary to use 
`const(char)[]`, but I never found convincing reasons to do so. 
My experience developing a real filesystem with **OXFuse** has 
shown that this decision was the right one.

Strictly speaking, paths should probably be represented as raw 
byte sequences such as `const(ubyte)[]`. However, `string` is 
still fundamentally just a byte sequence (not programmatically 
tied to any specific encoding), while also providing proper 
thread safety through immutability, improved readability, and 
mush better ergonomics in everiday use.



libfuse constantly spawns new POSIX threads when file operations 
are invoked. The main challenge when writing a D wrapper is 
correctly attaching those threads to the D-Runtime and detaching 
them afterward. D provides `thread_attachThis` and 
`thread_detachThis` for this purpose.

The difficult part is determing when a C thread created by 
libfuse is actually terminating. In **dfuse** this issue was 
never fully solved, and I myself arrived at a proper solution for 
**OXFuse** only recently:

```d
bool attached;
__gshared pthread_key_t detachKey;

shared static this() {
     pthread_key_create(&detachKey, &detach);
}

extern(C) void detach(void* ptr) nothrow {
     attached = false;
     collectException(thread_detachThis());
}

void attach() nothrow {
     if (!attached) {
         collectException(thread_attachThis());
         // create an association between current thread and the 
specified key
         pthread_setspecific(detachKey, cast(void*)1);
         attached = true;
     }
}
```

The `attach()` function is called for every file operation. When 
the underlying C thread is destroyed, our `detach()` function is 
guaranteed to be called because of the association with 
`pthread_key_t`.

As a result, the GC works correctly and there are no longer 
issues related to controlled filesystem shutdown. I am mentioning 
this here specifically for people who have run into problems 
coordinating C (pthread) threads with the D-Runtime.
May 19