From owner-freebsd-bugs@FreeBSD.ORG Thu Sep 20 22:00:16 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3578716A46D for ; Thu, 20 Sep 2007 22:00:16 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 169A413C4CB for ; Thu, 20 Sep 2007 22:00:15 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id l8KM0FfA055935 for ; Thu, 20 Sep 2007 22:00:15 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id l8KM0Fc2055932; Thu, 20 Sep 2007 22:00:15 GMT (envelope-from gnats) Date: Thu, 20 Sep 2007 22:00:15 GMT Message-Id: <200709202200.l8KM0Fc2055932@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Bruce Evans Cc: Subject: Re: bin/116477: rm behaves unexpectedly when using -r and relative paths X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Bruce Evans List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Sep 2007 22:00:16 -0000 The following reply was made to PR bin/116477; it has been noted by GNATS. From: Bruce Evans To: Justin Mitchell Cc: freebsd-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org Subject: Re: bin/116477: rm behaves unexpectedly when using -r and relative paths Date: Thu, 20 Sep 2007 21:45:20 +1000 (EST) On Wed, 19 Sep 2007, Justin Mitchell wrote: >> Description: > This is a bug with the 'rm' commandline utility that can cause data > loss. This is rm doing what you asked it to. > When using 'rm -r' with relative paths and a trailing slash rm can > delete the wrong item, or no item at all. Here is an example of rm > deleting the wrong file. > > mac:~ $ mkdir tmp > mac:~ $ cd tmp > mac:~/tmp $ mkdir test > mac:~/tmp $ ln -s test test2 > mac:~/tmp $ ls -l > total 8 > drwxr-xr-x 2 justin justin 68 Aug 10 01:41 test > lrwxr-xr-x 1 justin justin 4 Aug 10 01:42 test2 -> test > mac:~/tmp $ cd .. > mac:~ $ rm -r tmp/test2/ > mac:~ $ ls -l tmp > total 8 > lrwxr-xr-x 1 justin justin 4 Aug 10 01:42 test2 -> test > > Note that if you do you not use the trailing slash in 'rm -f tmp/ > test2/' that it will behave normally. It will also behave normally if > you do not 'cd' to another directory. > > I confirmed this with another individual running OS X, but I do > not know the version. For comparison, I tested this with an older > version of Redhat, and it worked fine. gnu/Linux rm or Linux could easily have a bug like that, but at least the version in an old FreeBSD package (linux_base-8-8.0_4 with bin/rm dated Sep 2 2002) works correctly under FreeBSD -- it removes the directory. > I submitted this bug report to Apple, but they said "This is how FreeBSD operates and rm is based on their sources." This is how symbolic links work. The trailing slash causes the symlink to be followed. POSIX spec: trailing slashes shall be resolved as if a single dot character were appended to a pathname. Hmm, this seems to require a small part behaviour that you want -- the pathname ends up with a trailing dot no matter where in the process of pathname resolution that the dot is added. Then rm(1)'s and/or rmdir(2)'s (bogus) restriction on removing "." and ".." comes into play and according to POSIX should prevent the removal of the directory pointed to by the symlink (but not the contents of the directory -- see below). What FreeBSD does is follow "test2/" to resolve to "test". It doesn't add the dot as required by POSIX. POSIX doesn't seem to say clearly when the dot should be added, but it would have to be added at the beginning of pathname resolution to be useful, since then it would cause "test2/" to be resolved to "test/.", while adding it after resolving to "test" would give the name "test." where the dot doesn't have anything to do with the directory entry "." and just messes up the name "test". After resolving to "test/.", rmdir() on the directory must fail due to rmdir()'s bogus restriction on removing ".". This restriction is bogus because it is only by name -- you can easily rmdir() your current directory (if it is empty) by spelling its name differently, e.g., as the absolute path to th current directory, but you can't dubdirectories if you spell their name with a ".". Before I started writing this mail, I thought that you could use the spelling of "/" to remove current and other directories, but the POSIX spec prevents that. However, the POSIX spec doesn't affect removing the directories entire contents using "rm -r /". rm has its own bogus restriction on removing "." (and "..") by name. This restriction doesn't apply here since there is no dot in "/". The pathname resolution that POSIX requires to add the dot occurs entirely in the kernel. Thus the expected behaviour for a POSIX "rm -r test2/" is: follow the symlink to get "test/." remove the contents of "test/." rm will probably just apply rm -r to each file in "test/.". I verified that the Linux rm from 2002 when run under FreeBSD just chdir()'s into any subdirs to remove them recursively. fail with errno EINVAL trying to rmdir() "test/." (the Linux rm from 2002 just tries to remove "test/", and this succeeds under FreeBSD) don't remove the symlink This is not what you want -- it removes everything except the one thing that is easy to recover. and the expected behaviour for a FreeBSD "rm -r test2/" is: same as above, except it won't fail on the top-level rmdir(). I know too much about this because I broke following of symlinks for "/" when fixing the handling of trailing slashes in general. Some other cases of interest: (1) when test2 is symlink to "test" and "test" doesn't exist at the start of each of the following operations: FreeBSD mkdir test2/ succeeds FreeBSD mkdir test2/. fails with errno ENOENT (reasonable, since test2 exists, but test2/ and test2/, don't) POSIX mkdir test2/ must fail after adding dot (2) when "test" doesn't exist at the start: FreeBSD mkdir test succeeds, nothing special FreeBSD mkdir test/ succeeds (tricky to make this work) FreeBSD mkdir test/. fails with ENOENT POSIX mkdir test/ ? POSIX says that trailing slashes shall be ignored in directory contexts. FreeBSD considers this to be a directory context (3) cases involving rename(2) are more complicated, and cases involving mv(1) are even more complicated, since mv to a directory has to manage pathnames before calling rename(2). Bruce