Date: Sun, 11 Feb 2001 23:09:44 +0100 (CET) From: mkamm@gmx.net To: FreeBSD-gnats-submit@freebsd.org Subject: bin/25013: mv(1) cannot move unresolvable symlinks across devices Message-ID: <200102112209.f1BM9iB02125@homebox.kammerhofer.org>
next in thread | raw e-mail | index | archive | help
>Number: 25013
>Category: bin
>Synopsis: mv(1) cannot move unresolvable symlinks across devices
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sun Feb 11 14:50:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: Martin Kammerhofer
>Release: FreeBSD 4.2-STABLE i386
>Organization:
Universität 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:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200102112209.f1BM9iB02125>
