digitalmars.D.announce - FUSE (Filesystem in Userspace) and OXFuse
- Vindex9 (80/80) May 19 I have been developing [my own
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








Vindex9 <tech.vindex gmail.com>