cvs commit: src/bin/cp cp.1

Tom Rhodes trhodes at FreeBSD.org
Thu Feb 24 23:28:53 GMT 2005


On Fri, 25 Feb 2005 05:37:20 +1100 (EST)
Bruce Evans <bde at zeta.org.au> wrote:

> 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.

In my case, I was using the period to end the sentence, not to
cover the "." entry in the file system.

With regards to English, I was always taught that you end a sentence
with punctuation in quotes; however, this rule may be broken when
confusion may occur.  This seems to be one of those cases and I
double checked with my friend, Matt, who teaches college
English courses.

> 
> >
> >   PR:             75774
> >   Submitted by:   Mike Meyer <mwm at mired.org> (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.

I had to read that paragraph twice.

> % 			 *
> % 			 * 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
> 

So, do you want to fix the bugs or should I just move the part
I added into a BUGS section?

-- 
Tom Rhodes


More information about the cvs-all mailing list