From owner-cvs-all@FreeBSD.ORG Thu Feb 24 18:37:27 2005 Return-Path: Delivered-To: cvs-all@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 7D18416A4CE; Thu, 24 Feb 2005 18:37:27 +0000 (GMT) Received: from mailout1.pacific.net.au (mailout1.pacific.net.au [61.8.0.84]) by mx1.FreeBSD.org (Postfix) with ESMTP id CBA0143D39; Thu, 24 Feb 2005 18:37:26 +0000 (GMT) (envelope-from bde@zeta.org.au) Received: from mailproxy2.pacific.net.au (mailproxy2.pacific.net.au [61.8.0.87])j1OIbNA6018240; Fri, 25 Feb 2005 05:37:23 +1100 Received: from katana.zip.com.au (katana.zip.com.au [61.8.7.246]) j1OIbLMq031847; Fri, 25 Feb 2005 05:37:22 +1100 Date: Fri, 25 Feb 2005 05:37:20 +1100 (EST) From: Bruce Evans X-X-Sender: bde@delplex.bde.org To: Tom Rhodes In-Reply-To: <200502240006.j1O06MDs099490@repoman.freebsd.org> Message-ID: <20050225042045.L99633@delplex.bde.org> References: <200502240006.j1O06MDs099490@repoman.freebsd.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII cc: cvs-src@freebsd.org cc: src-committers@freebsd.org cc: cvs-all@freebsd.org Subject: Re: cvs commit: src/bin/cp cp.1 X-BeenThere: cvs-all@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: CVS commit messages for the entire tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Feb 2005 18:37:27 -0000 On Thu, 24 Feb 2005, Tom Rhodes wrote: > trhodes 2005-02-24 00:06:22 UTC > > FreeBSD src repository > > Modified files: > bin/cp cp.1 > Log: > Note how cp(1) handles directories ending in "/." I think you mean ones ending in "/". Ones ending in "/." are similarly mishandled, but this is not noted. The strange English rule for putting "." in quotes is very confusing here. I don't know the exact rule. > > PR: 75774 > Submitted by: Mike Meyer (original version) This is a bug in cp.c, not in cp.1. cp starts getting confused here: % /* % * If we are in case (2) or (3) above, we need to append the % * source name to the target name. % */ % if (type != FILE_TO_FILE) { % /* % * Need to remember the roots of traversals to create % * correct pathnames. If there's a directory being % * copied to a non-existent directory, e.g. % * cp -R a/dir noexist % * the resulting path name should be noexist/foo, not % * noexist/dir/foo (where foo is a file in dir), which % * is the case where the target exists. % * % * Also, check for "..". This is for correct path % * concatenation for paths ending in "..", e.g. % * cp -R .. /tmp % * Paths ending in ".." are changed to ".". This is % * tricky, but seems the easiest way to fix the problem. % * % * XXX % * Since the first level MUST be FTS_ROOTLEVEL, base % * is always initialized. % */ % if (curr->fts_level == FTS_ROOTLEVEL) { % if (type != DIR_TO_DNE) { % p = strrchr(curr->fts_path, '/'); % base = (p == NULL) ? 0 : % (int)(p - curr->fts_path + 1); % % if (!strcmp(&curr->fts_path[base], % "..")) % base += 1; % } else % base = curr->fts_pathlen; % } It needs to strip to the basename, but for source file names ending in a slash, it strips everything. This is handled correctly in basename(3). OTOH, cp needs something special for "foo/.." and basename() doesn't do the right thing for that (it gives ".."). Somehow stripping "foo/.." to "." doesn't give the same result as stripping "foo/." to ".". There is an interesting subcase of this bug for symlinks. After: mkdir /tmp/z cd /tmp/z mkdir a1 b ln -s a1 a "cp -R a/ b" copies nothing but succeeds (wrong), but part of "cp -pR a/ b" thinks that the other part copied something and fails trying to change the attributes: %%% cp: utimes: b/a: No such file or directory cp: chown: b/a: No such file or directory cp: chmod: b/a: No such file or directory cp: chflags: b/a: No such file or directory %%% Then after putting a file in "a1", "cp -R a/ b" just copies the wrong thing (it follows the symlink OK but then copies the contents of the directory pointed to by the symlink when it should copy the directory itself) and then "cp -pR" doesn't try to change the attributes of a nonexistent file. The case of a trailing slash is most important for symlinks since it is the only way to get "cp -R" to follow the symlink. Bruce