How does one atomically change a symlink to a directory in busybox?
This can indeed be done atomically with rename(2)
, by first creating the new symlink under a temporary name and then cleanly overwriting the old symlink in one go. As the man page states:
If newpath refers to a symbolic link the link will be overwritten.
In the shell, you would do this with mv -T
as follows:
$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z
You can strace
that last command to make sure it is indeed using rename(2)
under the hood:
$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z") = 0
Note that in the above, both mv -T
and strace
are Linux-specific.
On FreeBSD, use mv -h
alternately.
Picking up where Arto left off here, this is entirely possible, even without mv -T
, you just need to create a new symlink with the same name as the target directory and mv
it into the parent directory of your target:
mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./
Code example taken via (http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/)
Have you tried ln -snf
?
The option -n
overwrites the destination rather than writing under it when the destination is a symbolic link to a directory.
Cheers