From mkamm@sbox.tu-graz.ac.at  Sun Feb 11 14:43:42 2001
Return-Path: <mkamm@sbox.tu-graz.ac.at>
Received: from ns1.tu-graz.ac.at (ns1.tu-graz.ac.at [129.27.2.3])
	by hub.freebsd.org (Postfix) with ESMTP id A5CEF37B401
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 11 Feb 2001 14:43:41 -0800 (PST)
Received: from homebox.kammerhofer.org (isdn091.tu-graz.ac.at [129.27.240.91])
	by ns1.tu-graz.ac.at (8.9.3/8.9.3) with ESMTP id XAA07806
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 11 Feb 2001 23:43:37 +0100 (MET)
Received: (from mkamm@localhost)
	by homebox.kammerhofer.org (8.11.2/8.11.2) id f1BM9iB02125;
	Sun, 11 Feb 2001 23:09:44 +0100 (CET)
	(envelope-from mkamm)
Message-Id: <200102112209.f1BM9iB02125@homebox.kammerhofer.org>
Date: Sun, 11 Feb 2001 23:09:44 +0100 (CET)
From: mkamm@gmx.net
Reply-To: mkamm@gmx.net
To: FreeBSD-gnats-submit@freebsd.org
Subject: mv(1) cannot move unresolvable symlinks across devices
X-Send-Pr-Version: 3.2

>Number:         25013
>Category:       bin
>Synopsis:       mv(1) cannot move unresolvable symlinks across devices
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 11 14:50:01 PST 2001
>Closed-Date:    Mon May 24 15:29:29 UTC 2010
>Last-Modified:  Mon May 24 15:29:29 UTC 2010
>Originator:     Martin Kammerhofer
>Release:        FreeBSD 4.2-STABLE i386
>Organization:
Universitt Graz
>Environment:
>Description:

Unresolvable symlinks cannot be moved across devices with mv(1).

>How-To-Repeat:

I assume that /tmp and $HOME are on different devices:
$ ln -sf /GENERIC /tmp/generic
$ mv /tmp/generic ~ # this does work

Now I try to move a broken symlink
$ ln -sf /NOSUCH /tmp/nosuch
$ mv /tmp/nosuch ~ # this does work too

Finally I trigger the bug:
$ ln -sf /NODIR/NOFILE /tmp/nofile
$ mv /tmp/nofile ~
mv: cannot resolve /tmp/nofile: /NODIR

Even option -f doesn't help here.

>Fix:

The problem was introduced with a code snippet that protects against
moving mountpoints. Moving mountpoints is bad, because that would
trigger "cp -pRP /mountpoint newname".  My patch invokes this code
snippet only if a directory is to be moved and bypasses it otherwise.
(My patch also tries to avoid redundant lstat(2) calls.)

Index: mv.c
===================================================================
RCS file: /home/ncvs/src/bin/mv/mv.c,v
retrieving revision 1.27
diff -u -r1.27 mv.c
--- mv.c	2000/07/20 18:30:00	1.27
+++ mv.c	2001/02/10 03:51:23
@@ -152,10 +152,11 @@
 do_move(from, to)
 	char *from, *to;
 {
-	struct stat sb;
-	int ask, ch, first;
+	struct stat sb_from, sb;
+	int ask, ch, first, got_from;
 	char modep[15];
 
+	got_from = 0; /* lstat of "from" not done yet */
 	/*
 	 * Check access.  If interactive and file exists, ask user if it
 	 * should be replaced.  Otherwise if file exists but isn't writable
@@ -164,10 +165,11 @@
 	if (!fflg && !access(to, F_OK)) {
 
 		/* prompt only if source exist */
-	        if (lstat(from, &sb) == -1) {
+	        if (lstat(from, &sb_from) == -1) {
 			warn("%s", from);
 			return (1);
 		}
+		got_from = 1;
 
 #define YESNO "(y/n [n]) "
 		ask = 0;
@@ -202,6 +204,14 @@
 		struct statfs sfs;
 		char path[MAXPATHLEN];
 
+		/* if from isn't a directory it can't be a mount point */
+	        if (!got_from && lstat(from, &sb_from) == -1) {
+			warn("%s", from);
+			return (1);
+		}
+		if (!S_ISDIR(sb_from.st_mode))
+		    goto copy_it;
+		    
 		/* Can't mv(1) a mount point. */
 		if (realpath(from, path) == NULL) {
 			warnx("cannot resolve %s: %s", from, path);
@@ -221,12 +231,13 @@
 	 * it's a regular file, do the copy internally; otherwise, use
 	 * cp and rm.
 	 */
-	if (lstat(from, &sb)) {
+	if (!got_from && lstat(from, &sb_from)) {
 		warn("%s", from);
 		return (1);
 	}
-	return (S_ISREG(sb.st_mode) ?
-	    fastcopy(from, to, &sb) : copy(from, to));
+ copy_it:
+	return (S_ISREG(sb_from.st_mode) ?
+	    fastcopy(from, to, &sb_from) : copy(from, to));
 }
 
 int

>Release-Note:
>Audit-Trail:

From: Bruce Evans <bde@zeta.org.au>
To: mkamm@gmx.net
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/25013: mv(1) cannot move unresolvable symlinks across devices
Date: Mon, 12 Feb 2001 16:18:49 +1100 (EST)

 On Sun, 11 Feb 2001 mkamm@gmx.net wrote:
 
 > Unresolvable symlinks cannot be moved across devices with mv(1).
 > ...
 > >Fix:
 > 
 > The problem was introduced with a code snippet that protects against
 > moving mountpoints. Moving mountpoints is bad, because that would
 > trigger "cp -pRP /mountpoint newname".  My patch invokes this code
 > snippet only if a directory is to be moved and bypasses it otherwise.
 > (My patch also tries to avoid redundant lstat(2) calls.)
 
 I think the "protection" should just be removed.  POSIX.2 doesn't
 mention a special case for mountpoints (at least least in my old draft
 copy that doesn't specify mountpoints :-).  Moving a huge directory
 may be a mistake whether or not the directory is a mountpoint.  It is
 practically impossible to "protect" against moving mountpoints deep
 in the hierarchy.
 
 I think that POSIX.2 and/or BSD made a mistake here, and mv should never
 move across filesystems without being forced to.  gnu mv still refuses
 to move across filesystems in the last version that I have handy (a
 Feb 26 1997 Redhat version running under FreeBSD; this also has emulation
 problems -- "mv /tmp/q /usr" attempted to move the directory to
 /compat/linux/usr/q).
 
 Bruce
 
 
State-Changed-From-To: open->closed 
State-Changed-By: jh 
State-Changed-When: Mon May 24 15:29:28 UTC 2010 
State-Changed-Why:  
Fixed in r62963. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=25013 
>Unformatted:
