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

2012-08-29 Thread Gary Jennejohn
On Tue, 28 Aug 2012 10:58:09 -0400
John Baldwin j...@freebsd.org 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?
 
[snip patch]

Nope, seems like a reasonable extension to me (gj@).

-- 
Gary Jennejohn
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


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

2012-08-29 Thread Jilles Tjoelker
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).

-- 
Jilles Tjoelker
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


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

2012-08-29 Thread John Baldwin
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=lnapropos=0sektion=0manpath=SuSE+Linux%2Fi386+11.3arch=defaultformat=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
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


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

2012-08-29 Thread Jilles Tjoelker
On Wed, Aug 29, 2012 at 08:09:20AM -0400, John Baldwin wrote:
 On Wednesday, August 29, 2012 6:02:47 am Jilles Tjoelker wrote:
  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=lnapropos=0sektion=0manpath=SuSE+Linux%2Fi386+11.3arch=defaultformat=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).

Coreutils ln -n is the same as our ln -h, and we already have
compatibility for it.

The coreutils -T option is different, though. It forces the ln
source_file target_file synopsis instead of the ln source_file ...
target_dir synopsis, without checking the type of the final operand. If
there are not exactly two operands, a syntax error occurs. If the final
operand is a directory and cannot be overwritten, an error occurs.

-- 
Jilles Tjoelker
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


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

2012-08-29 Thread John Baldwin
On Wednesday, August 29, 2012 3:32:13 pm Jilles Tjoelker wrote:
 On Wed, Aug 29, 2012 at 08:09:20AM -0400, John Baldwin wrote:
  On Wednesday, August 29, 2012 6:02:47 am Jilles Tjoelker wrote:
   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=lnapropos=0sektion=0manpath=SuSE+Linux%2Fi386+11.3arch=defaultformat=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).
 
 Coreutils ln -n is the same as our ln -h, and we already have
 compatibility for it.

Bah, not sure how I missed the -n previously.

 The coreutils -T option is different, though. It forces the ln
 source_file target_file synopsis instead of the ln source_file ...
 target_dir synopsis, without checking the type of the final operand. If
 there are not exactly two operands, a syntax error occurs. If the final
 operand is a directory and cannot be overwritten, an error occurs.

Ah, this is not quite what my mv -h patch does.  It does not error if the
destination is a directory.  It is much closer to ln -h and exactly matches
the language for ln -n I quoted above.

-- 
John Baldwin
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org


[PATCH] Add a -h flag to mv

2012-08-28 Thread John Baldwin
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?

Index: mv.1
===
--- mv.1(revision 239731)
+++ mv.1(working copy)
@@ -32,7 +32,7 @@
 .\@(#)mv.18.1 (Berkeley) 5/31/93
 .\ $FreeBSD$
 .\
-.Dd May 12, 2007
+.Dd August 28, 2012
 .Dt MV 1
 .Os
 .Sh NAME
@@ -41,7 +41,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl f | i | n
-.Op Fl v
+.Op Fl hv
 .Ar source target
 .Nm
 .Op Fl f | i | n
@@ -81,6 +81,21 @@
 or
 .Fl n
 options.)
+.It Fl h
+If the
+.Ar target
+operand is a symbolic link to a directory,
+do not follow it.
+This causes the
+.Nm
+utility to rename the file
+.Ar source
+to the destination path
+.Ar target
+rather than moving
+.Ar source
+into the directory referenced by
+.Ar target .
 .It Fl i
 Cause
 .Nm
@@ -142,7 +157,8 @@
 .Ex -std
 .Sh COMPATIBILITY
 The
-.Fl n
+.Fl h ,
+.Fl n ,
 and
 .Fl v
 options are non-standard and their use in scripts is not recommended.
Index: mv.c
===
--- mv.c(revision 239731)
+++ mv.c(working copy)
@@ -68,7 +68,7 @@
 /* Exit code for a failed exec. */
 #define EXEC_FAILED 127
 
-static int fflg, iflg, nflg, vflg;
+static int fflg, hflg, iflg, nflg, vflg;
 
 static int copy(const char *, const char *);
 static int do_move(const char *, const char *);
@@ -87,8 +87,11 @@
int ch;
char path[PATH_MAX];
 
-   while ((ch = getopt(argc, argv, finv)) != -1)
+   while ((ch = getopt(argc, argv, fhinv)) != -1)
switch (ch) {
+   case 'h':
+   hflg = 1;
+   break;
case 'i':
iflg = 1;
fflg = nflg = 0;
@@ -123,6 +126,17 @@
exit(do_move(argv[0], argv[1]));
}
 
+   /*
+* If -h was specified, treat the target as a symlink instead of
+* directory.
+*/
+   if (hflg) {
+   if (argc  2)
+   usage();
+   if (lstat(argv[1], sb) == 0  S_ISLNK(sb.st_mode))
+   exit(do_move(argv[0], argv[1]));
+   }
+
/* It's a directory, move each file into it. */
if (strlen(argv[argc - 1])  sizeof(path) - 1)
errx(1, %s: destination pathname too long, *argv);
@@ -483,7 +497,7 @@
 {
 
(void)fprintf(stderr, %s\n%s\n,
- usage: mv [-f | -i | -n] [-v] source target,
+ usage: mv [-f | -i | -n] [-hv] source target,
 mv [-f | -i | -n] [-v] source ... directory);
exit(EX_USAGE);
 }

-- 
John Baldwin
___
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to freebsd-current-unsubscr...@freebsd.org