REWRITEFS(1)

πŸ“¦
version 0-unstable-2026-08 Β· 2 versions
, in nixpkgs unstable

✨ rewritefs(1) β€” mod_rewrite-like FUSE filesystem ✨

bestie, welcome to the rewritefs(1) manual πŸ’… this is literally the page for a FUSE filesystem that rewrites file names on the fly, and it’s giving β€œdotfiles but make it fashion.” let’s go 🫢


πŸ’… NAME πŸ’…

rewritefs β€” mod_rewrite-like FUSE filesystem

🌸 Description 🌸

rewritefs is a FUSE filesystem similar to web servers’ mod_rewrite. It can change the name of accessed files on-the-fly ✨

The short story: I needed a tool to manage my dotfiles. I forked Luc DufreneΒ΄s libetc [http://ordiluc.net/fs/libetc/] after it seemed unmaintained. Here is its description:

Unfortunately, I eventually run into LD_PRELOAD problems (mainly with programs using dlopen like VirtualBox and screen). So I decided to rewrite it using FUSE, and make it more generic πŸ˜­πŸ’–

πŸ’– Dependencies πŸ’–

fuse3 & pcre2. That’s all.

To use contexts, you need /proc/(pid)/cmdline. But don’t use contexts if you can avoid it ! πŸ‘‘

πŸŽ€ Installation πŸŽ€

make && sudo make install

πŸ¦‹ Configuration πŸ¦‹

For a complete description of the configuration syntax format, see below.

Make sure that user_allow_other is enabled in /etc/fuse.conf 🌸

✨ Example 1 ✨

The following example demonstrates how one can get the program to do what libetc does :

m#^(?!\.)# .
m#^\.(cache|config|local)# .
m#^\.# .config/

That is, all dotfiles will be put in .config/ (without the leading dot), excepting .cache and .local πŸ’…

🌈 Example 2 🌈

This example show how to use contexts ; it is like the former, but ignore the rewrite rules for busybox:

m#^(?!\.)# .
m#^\.(cache|config|local)# .
- /^\S*busybox/
/^/ .
- //
m#^\.# .config/

πŸ’œ Usage πŸ’œ

Once you have written your configuration file, you use rewritefs to mount the β€œrewritten” filesystem, for example :

rewritefs -o config=/mnt/home/me/.config/rewritefs /mnt/home/me /home/me

Then, accessing to files in /home/me will follow rules defined in your config file ✨

πŸ“ Directory auto-creation πŸ“

When using backreferences of in rules of the form…

/(.+) - (.+)/ \1/\2

…it is possible that the directory into which an operation is being redirected does not exist yet. To support such rules, rewritefs may be invoked with the option -o autocreate. This option will cause rewritefs to automatically create all non-existing parent directories when a path is being rewritten.

Note that, due to FUSE limitations, the parent directories will be created using the umask with which rewritefs has been invoked, instead of the umask of the process requesting accessing the file πŸ‘€

πŸ”₯ Using rewritefs with mount(8) or fstab(5) πŸ”₯

rewritefs /mnt/home/me /home/me -o config=/mnt/home/me/.config/rewritefs,allow_other

allow_other and default_permissions is here to allow standards users to access the filesystem with standard permissions.

So, you can use the fstab entry:

/mnt/home/me /home/me fuse.rewritefs config=/mnt/home/me/.config/rewritefs,allow_other 0 0

See mount.fuse(8) for all FUSE options 🫢

πŸ‘‘ Using rewritefs with pam_mount(8) πŸ‘‘

Let’s suppose that you want to use rewritefs to replace libetc (it’s its primary goal, after all). You need to mount the rewritefs on your home when you login. This can be achieved with pam_mount.

Let’s say you have your raw home dirs in /mnt/home/$USER. Then, to use rewritefs on /home/$USER with configuration file stored at /mnt/home/$USER/.config/rewritefs, you need to add this to pam_mount.xml:

<volume fstype="fuse" path="rewritefs##/mnt/home/%(USER)" mountpoint="~"
     options="config=/mnt/home/%(USER)/.config/rewritefs,allow_other" />

You can add user="me" to limit this to yourself (but think to create symlinks for other users !)

Don’t forget to activate pam_mount in your pam configuration too. This is distribution-dependent ; you have to refer to the corresponding documentation πŸ’€

πŸ’€ FAQ πŸ’€

Q: I installed rewritefs with the default config, and now ls returns me something like that :

ls: cannot access /home/user/.vimrc: No such file or directory
ls: cannot access /home/user/.zshrc: No such file or directory
d????????? ? ? ? ? ? .ssh/

Short answer: You have to manually move .vimrc, zshrc, .ssh/ inside .config before using rewritefs.

Long answer: If .ssh is translated (by the rules you gave to rewritefs) into .config/ssh, and that you didn’t renamed .ssh into .config/ssh yourself (i.e. that .ssh still exists and .config/ssh doesn’t exists on the original filesystem), that’s the intended behavior.

Rewritefs does not rewrite readdir(), since it would need β€œbackwards” rewriting (and that’s not technically possible, since the rules are defined using regular expressions). ls calls readdir(), which returns .ssh. ls then tries to call stat(".ssh") to find metadata (permissions, mtime and so on), which is rewritten into stat(".config/ssh") which does not exists, hence this error 😭

🌟 Configuration syntax format 🌟

🧚 Regular expressions 🧚

The Regexp syntax is similar to Perl. Recognized flags are : i, x, u and g. Example of valid regexps are:

/foo/i
m/fOo/u
m/dev\/null/
m|tata|
m|This\sis
    \san\sextended
    \sregexep|x

Note that m{foo} is not recognized ; you must use m{foo{

i and x has the same meaning than in Perl. u means β€œuse utf-8” (both for pattern and input string).

The g flag is described in the β€œRewrite rule” section.

⭐ Command line match ⭐

Syntax:

- REGEXP

Limit the following rules to programs matching REGEXP (comparing with the content of /proc/(pid)/cmdline, replacing null characters with spaces)

πŸ’… Rewrite rule πŸ’…

Syntax:

REGEXP rewritten-path

A file matching REGEXP will be rewritten to rewritten-path. To be more accurate, the matched data will be replaced by rewritten-path in the filename. For example, with this rule:

/fo/ ba

accessing to foo will be translated into bao. > Warning: if you don’t start your regexp with ^, information will be rewritten into inbamation !

If rewritten-path is ., it means β€œdonΒ΄t rewrite anything”.

. and .. will never be proposed to be translated.

You can access captured groups as backreferences (\1, \2, …).

A regular expression can be written in more than one line, in particular in conjunction with the x flag.

The g flag indicates that the substition is global, and not limited to the first match. Consider this simple rule:

/:/ -

Applied to A:B:C, the rewritten path will be A-B:C. With the g flag, the rewritten path will be A-B-C ✨

πŸŽ€ Comment πŸŽ€

A line starting with #

πŸš€ Performances πŸš€

Some rules to keep the overhead smallest possible :

  • use the fast pruning technique described in config.example
  • avoid using contexts whenever you can
  • avoid using backreferences in your regexp (\1)
  • avoid using backreferences in your rewritten path. You can generally avoid them by using lookarounds.

For example, instead of writing:

/\.(gtk-bookmarks|mysql_history)/ .cache/\1

you can write the more efficient:

/\.(?=gtk-bookmarks|mysql_history)/ .cache/

I urge you to read β€œMastering regular expressions” if you want to make rules substantially different from the example πŸ’–


β€” REWRITEFS(1), January 2020. byeee πŸ’…πŸŽ€

πŸ“¦ where this page comes from