linuxunixdirectoryfilenamesslash

Is it possible to use "/" in a filename?


I know that this is not something that should ever be done, but is there a way to use the slash character that normally separates directories within a filename in Linux?


Solution

  • The answer is that you can't, unless your filesystem has a bug. Here's why:

    There is a system call for renaming your file defined in fs/namei.c called renameat:

    SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
                    int, newdfd, const char __user *, newname)
    

    When the system call gets invoked, it does a path lookup (do_path_lookup) on the name. Keep tracing this, and we get to link_path_walk which has this:

    static int link_path_walk(const char *name, struct nameidata *nd)
    {
           struct path next;
           int err;
           unsigned int lookup_flags = nd->flags;
           
           while (*name=='/')
                  name++;
           if (!*name)
                  return 0;
    ...
    

    This code applies to any file system. What's this mean? It means that if you try to pass a parameter with an actual '/' character as the name of the file using traditional means, it will not do what you want. There is no way to escape the character. If a filesystem "supports" this, it's because they either:

    Furthermore, if you did go in and edit the bytes to add a slash character into a file name, bad things would happen. That's because you could never refer to this file by name :( since anytime you did, Linux would assume you were referring to a nonexistent directory. Using the 'rm *' technique would not work either, since bash simply expands that to the filename. Even rm -rf wouldn't work, since a simple strace reveals how things go on under the hood (shortened):

    $ ls testdir
    myfile2 out
    $ strace -vf rm -rf testdir
    ...
    unlinkat(3, "myfile2", 0)               = 0
    unlinkat(3, "out", 0)                   = 0
    fcntl(3, F_GETFD)                       = 0x1 (flags FD_CLOEXEC)
    close(3)                                = 0
    unlinkat(AT_FDCWD, "testdir", AT_REMOVEDIR) = 0
    ...
    

    Notice that these calls to unlinkat would fail because they need to refer to the files by name.