Re: [PATCH] Add a "-h" flag to mv

From: John Baldwin <jhb_at_freebsd.org>
Date: Wed, 29 Aug 2012 08:09:20 -0400
On Wednesday, August 29, 2012 6:02:47 am Jilles Tjoelker wrote:
> On Tue, Aug 28, 2012 at 10:58:09AM -0400, John Baldwin wrote:
> > I have a use case at work where I need to be able to update a symlink
> > that points to a directory atomically (so that it points to a new
> > directory).  To give a conrete example, suppose I have two directories
> > 'foo' and 'bar', and a symlink 'a' that I wish to atomically flip from
> > 'foo' to 'bar'.
> 
> > Using 'ln -shf bar a' is not atomic as it uses separate unlink() and
> > symlink() system calls, so there is a race where another thread may
> > encounter ENOENT while traversing 'a'.
> 
> > The approach we used was to create a new symbolic link 'a.new' (e.g.
> > via 'ln -s bar a.new') and then use rename() to rename 'a.new' on top
> > of 'a'. Normally to do an atomic rename from userland one would use
> > 'mv', but 'mv a.new a' doesn't do that.  Instead, it moves 'a.new'
> > into the directory referenced by the 'a' symlink.  At work we have
> > resorted to invoking python's os.rename() in a one-liner to handle
> > this.
> 
> > While rehashing this discussion today it occurred to me that a -h flag to
> > mv would allow it to work in this case (and is very similar to how ln treats
> > its -h flag).  To that end, I have a patch to add a new -h flag to mv that
> > allows one to atomically update a symlink that points to a directory.  I
> > could not find any other mv commands that have adopted a -h (or a different
> > flag that accomplishes the same task).  Given that it functions identically
> > to the -h flag for ln, -h seemed the "logical" choice.  Any objections?
> 
> GNU coreutils mv (and also cp/install/ln) appears to use
> -T/--no-target-directory for a similar purpose: -T prevents the target
> being treated as a directory (whether it is a symlink or not).

Hmm, I could find no documentation for this online via Google searches or
the Linux manpages we have on www.FreeBSD.org.  Bah, Google just makes
searching for these sorts of things painful it seems (you have to put
explicit quotes around "--no-target-directory" for it to actually be used).
Also, it seems I just chose all the wrong Linux manpage sets to look at.

It seems that Linux's -T flag is similar to -h for ln as well.  I don't think
we can deprecate -h for ln, but perhaps we could add -T as a compat flag to
ln and mv?  I'd be inclined to still add -h to mv so that it mirrors ln.

Hmm, it seems RedHat's ln uses -n for this (OpenBSD, NetBSD, and Darwin
all include a -n as an alias to -h for ln to support compat with other
operating systems).  OSF/1 (and Tru64) and SunOS use -n to mean "complain
if the file already exists" similar to 'mv -n'.  Also, looking at the
Suse manpage on www.FreeBSD.org, it seems their ln (which does have -T)
has both -n and -T with different descriptions, but to achieve the same
purpose:

http://www.freebsd.org/cgi/man.cgi?query=ln&apropos=0&sektion=0&manpath=SuSE+Linux%2Fi386+11.3&arch=default&format=html

       -n, --no-dereference
	      treat destination that is a symlink to a directory as if it were
	      a normal file

       -T, --no-target-directory
	      treat LINK_NAME as a normal file

(To me it seems LINK_NAME and destination are the same thing.)

My inclination would be to add -h to mv, but perhaps add -T as an alias
for -h to both ln and mv, and -n as an alias for -h to ln (if we want
aliases to match coreutils).

-- 
John Baldwin
Received on Wed Aug 29 2012 - 10:25:47 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:30 UTC