linuxbashfilesystemsatomicfile-rename

Moving a directory atomically


I have two directories in the same parent directory. Call the parent directory base and the children directories alpha and bravo. I want to replace alpha with bravo. The simplest method is:

rm -rf alpha
mv bravo alpha

The mv command is atomic, but the rm -rf is not. Is there a simple way in bash to atomically replace alpha with bravo? If not, is there a complicated way?

ADDENDUM:

By the by, it's not an insurmountable problem if the directory doesn't exist for a short period. There's only one place that tries to access alpha, and it checks if alpha exists before doing anything critical. If not, it gives an error message. But it would be nice if there was a way to do this. :) Maybe there's some way to modify the inodes directly, or something...


Solution

  • You can do this if you use symlinks:

    Let's say alpha is a symlink to directory alpha_1, and you want to switch the symlink to point to alpha_2. Here's what that looks like before the switch:

    $ ls -l
    lrwxrwxrwx alpha -> alpha_1
    drwxr-xr-x alpha_1
    drwxr-xr-x alpha_2
    

    To make alpha refer to alpha_2, use ln -nsf:

    $ ln -nsf alpha_2 alpha
    $ ls -l
    lrwxrwxrwx alpha -> alpha_2
    drwxr-xr-x alpha_1
    drwxr-xr-x alpha_2
    

    Now you can remove the old directory:

    $ rm -rf alpha_1
    

    Note that this is NOT actually a fully atomic operation, but it does happen very quickly since the "ln" command both unlinks and then immediately recreates the symlink. You can verify this behaviour with strace:

    $ strace ln -nsf alpha_2 alpha
    ...
    symlink("alpha_2", "alpha")             = -1 EEXIST (File exists)
    unlink("alpha")                         = 0
    symlink("alpha_2", "alpha")             = 0
    ...
    

    You can repeat this procedure as desired: e.g. when you have a new version, alpha_3:

    $ ln -nsf alpha_3 alpha
    $ rm -rf alpha_2