Hello everyboddy,
I have a (probably) stupid question... Please forgive me if she really is.
I "discovered" today a strange thing:$ mkdir foo
$ cp -R foo fooI was waiting something like "cannot copy a directory into himself" or
something like that but in fact this command create a (infinite ? I don't know
because I stop the action before the end) tree, like this:/foo/foo/foo/foo/foo/foo/foo...
Look like a bug for me. Isn't it ?
--
Rimi Bougard
This looks like fun ... 8-) And this is open source, so let's follow
the code and learn something as we go along ...But first, I guess it IS following your instructions ...
You asked it to copy what's in directory foo, recursively. And you
are changing what's in foo at the same time ...1. What's in foo? foo
2. So copy foo to foo - giving foo/foo.
3. What's in foo? foo/foo
4. So copy foo/foo to foo/foo/foo.
5. Repeat.Until it goes boom.
# mkdir foo
# cp foo foo
cp: foo is a directory (not copied).(Sorry for the long lines below - haven't quite figured out how to
stop that.)# mkdir foo
# cp -R foo foo
cp: foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo: name too long (not copied)
cp: foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/fo...
unfortunately, using strcmp fails in many cases where the directory
may be accessed using different pathnames. also, this doesn't address
the case of more than source argument.
I am afraid solving the general case is harder.
You would have to do a full tree search down into the directories
to copy and see if you find the destination anywhere. During the
tree scan you would have to use all rules about following
links that the actual copy recursion would use.And that would not be enough... I made a little test and if the
target contains directories that have the same name(s) as in
the source, they are retained (their inode number does not change).This should mean that the target may contain an arbitrarily deep
directory structure that on any point can hard link to somewhere
in the source directory structure, causing a cycle that is very
expensive to find, even if you do the cycle detection
during the copy recursion.The path length limit actually works as a crude, cheep and effective
cycle detection.While Windows Finder solves the simple case of copying into
yourself, I do not think it has solved the general case.
Anyone curious to try?--
/ Raimo Niskanen, Erlang/OTP, Ericsson AB
I might try a Linux install (got some Slackware 12.0 CDs) and look at
what it does (and its source code) - sure someone will beat me to it.Looks like OpenBSD, FreeBSD, and Mac OS X BSD bits have the same
sort of outcome.I got this from Tom Van Looy (thanks, Tom):
Copy foo to foo only once and quit, I think that's the correct
behaviour. I even think that posix more or less describes that.$ mkdir foo
$ cp -R foo foo
$ ls -R foo
foo/:
foofoo/foo:
That's what it should be doing I guess. But it's tricky, if you start
doing symlinks etc, you'll end up looping sooner or later. What if
the directoy's are not named the same (eg: hard links)?(please reply cc to the list)
And another email from Tom Van Looy:
Oh and yes, it doesn't go boom, the copy just stops when the max
filename length is reached (logically). And "<blablabla> name too
long (not copied)" is an error, you can just redirect it to dev null,
cp -R foo foo 2>/dev/null, if you don't like it on your screen.Try fixing it so that it doesn't copy a directory into itself when it
is allready copied (so allow it only once). GNU cp does something
like that:$ mkdir foo
$ cp -R foo foo
cp: cannot copy a directory, `foo', into itself, `foo/foo'
$ ls -R foo
foo:
foofoo/foo:
Only, I think the warning is not needed (and I didn't further test
it, so it's possibly doing something else after all).
correction: hard links are not allowed on directory's, ...
that being said, comparing inodes seems the best solutiononly, don't give an error but copy once
maybe if I have time this weekend I'll try code that behaviourAnyway, it has worked like that since years, and I guess nobody has had
a problem with it before. I don't think it should be changed just
because some bored guy playing with it noticed strange output ;-pRegards,
Tom
Sure, but "bored guy" can translate to "new ideas" and testing
somehow-still-untested code paths. It's worth a shot at fixing.-Nick
For what its worth, all I can offer is moral support since I don't code
C.Conceptually, though, why can't cp look at the source directory and take a
snapshot, a to-do-list, of everything it has to copy, then do it? That
way, any recursion would be completed before the target directory
appeared in the source directory. With only an -R (no -H -L or -P), it
should copy links as links which should avoid loops.How do scp and rsync do it?
Doug.
On Fri, Oct 19, 2007 at 01:52:03PM -0400, Douglas A. Tutty wrote:
| Conceptually, though, why can't cp look at the source directory and take a
| snapshot, a to-do-list, of everything it has to copy, then do it? That
| way, any recursion would be completed before the target directory
| appeared in the source directory. With only an -R (no -H -L or -P), it
| should copy links as links which should avoid loops.What will you do if the underlying directory structure has tons and
tons of files and subdirectories ? First traverse this entire tree,
keeping it all in memory ? Sounds pretty expensive.| How do scp and rsync do it?
Why not try it ? scp local to remote doesn't make sense in this case,
since src and dst are not really the same. scp local to local has the
exact same effect (you even get an error message from cp that the name
is too long).rsync does exactly what you just propose. It scans the entire src
directory structure, keeping it all in memory, and then copies that to
dst. If there's too many files in your hierarchy, rsync will fail. cp
will not (unless of course you run out of inodes).Cheers,
Paul 'WEiRD' de Weerd
+++++++++++>-]<.>++[<------------>-]<+.--------------.[-]
http://www.weirdnet.nl/
I believe that it is only necessary to do one directory read ahead in
order to avoid the recursive loop. (I just took a quick look at the cp
source in OpenBSD, so, correct me if I am wrong.)$ cp <source1> ... <sourceN> <directory>
We can read the contents of <source1> if source1 is a directory, then
create a directory in <directory> and copy the contents of source1 into
it, and then repeat. This should not cause an endless loop.--
((name "Aaron Hsu")
(email/xmpp "arcfide@sacrificumdeo.net")
(phone "703-597-7656")
(site "http://www.aaronhsu.com"))[demime 1.01d removed an attachment of type application/pgp-signature]
Could you scan the tree only for recursions? You wouldn't have to keep
it all in memory, only the problem points, maybe?None of this feels like the Right Way though.
-Nick
the other thing you can do is not copy directories into themselves.
it's very easy. i'm not copying a directory into itself right now. i
can even not do this while sleeping.
At linux 2.6.22 (Ubuntu 7.10)
$ mkdir foo
$ scp -r foo localhost:/home/spyro/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo: name too longUsing OpenSSH_4.6p1 Debian-5build1, OpenSSL 0.9.8e 23 Feb 2007
Well, given that I feel targeted by this sentence ;) I think I will look at
the cp's source code and try to "fix" that. Could be fun after all.--
Remi Bougard
ps: it was a ;-p
Ill try this on a solaris box and a linix box tomorrow at work :P
--
Best RegardsEdd
---------------------------------------------------
http://students.dec.bournemouth.ac.uk/ebarrett
I beat you to trying it on Linux (Ubuntu "Gutsy Gibbon" 7.10):
ropers@tranquility:~$ uname --all
Linux tranquility 2.6.22-14-386 #1 Sun Oct 14 22:36:54 GMT 2007 i686 GNU/Linux
ropers@tranquility:~$ echo $SHELL
/bin/bash
ropers@tranquility:~$ mkdir foo
ropers@tranquility:~$ cp -R foo foo
cp: cannot copy a directory, `foo', into itself, `foo/foo'
ropers@tranquility:~$IMHO cp behaving like this is somewhat nicer than its current
behaviour on apparently most or all BSD OSes. Then again, I STILL
can't code, so I've no right to complain. ;o)
No I didn't. Others beat me and you to it. Apologies for the unnecessary noise.
I'm surprised now.
I just thought that what I wrote above was stupid, because I thought
that the behaviour of cp was a function of the shell built-in command
cp, not of the OS.
To confirm this, I installed the OpenBSD default shell pdksh on
Ubuntu. However, pdksh on Ubuntu gives the same result as bash on
Ubuntu. So is this a function of the OS after all?| ropers@tranquility:~$ uname -a
| Linux tranquility 2.6.22-14-386 #1 Sun Oct 14 22:36:54 GMT 2007 i686 GNU/Linux
| ropers@tranquility:~$ echo $SHELL
| /bin/bashWe're on Linux and we're using bash.
| ropers@tranquility:~$ mkdir foo
| ropers@tranquility:~$ cp -r foo foo
| cp: cannot copy a directory, `foo', into itself, `foo/foo'Bash behaves as expected.
| ropers@tranquility:~$ sudo apt-get install pdksh
| Reading package lists... Done
| Building dependency tree
| Reading state information... Done
| The following NEW packages will be installed:
| pdksh
| 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
| Need to get 0B/261kB of archives.
| After unpacking 442kB of additional disk space will be used.
| Selecting previously deselected package pdksh.
| (Reading database ... 167230 files and directories currently installed.)
| Unpacking pdksh (from .../pdksh_5.2.14-20build1_i386.deb) ...
| Setting up pdksh (5.2.14-20build1) ...Ok, now pdksh is installed.
| ropers@tranquility:~$ pdksh
| $ ps | grep sh
| 6567 pts/0 00:00:00 bash
| 6816 pts/0 00:00:00 pdksh
| 6818 pts/0 00:00:00 pdkshNow we're running pdksh (echo $SHELL isn't changed when launching
another shell interactively, hence the use of ps to confirm).| $ rm -rf foo
Need to rm foo to start from scratch.
| $ mkdir foo
| $ cp -r foo foo
| cp: cannot copy a directory, `foo', into itself, `foo/foo'Strange.
pdksh on Linux behaves just like bash on Linux, and unlike pdksh on OpenBSD.
I didn't expect that. So does that error messa...
It's official: I am a fucking moron.
cp is not a SHELL BUILTIN COMMAND. It's /bin/cp. And of course the
same /bin/cp is run regardless which shell is being used. That
explains the identical error message.Sorry for the noise.
Hello,
cp is part of the libc.
--
Remi Bougard
the behavior of the cp program depends on which cp program you are
or not.
On 2007 Oct 18, at 4:40 PM, Edd Barrett wrote:
> On 18/10/2007, Richard Toohey <richardtoohey@paradise.net.nz> wrote:
>
>>> $ mkdir foo
>>> $ cp -R foo foo
>
> Ill try this on a solaris box and a linix box tomorrow at work :PMac OS X 10.4 behaves exactly the same way as OpenBSD does.
Cheers,
b&
[demime 1.01d removed an attachment of type application/pkcs7-signature which had a name of smime.p7s]
For what's it's worth, this is what OS X decides:
Axkbk:~ kousu$ mkdir test
Axkbk:~ kousu$ cd test/
Axkbk:~/test kousu$ mkdir foo
Axkbk:~/test kousu$ cp -r foo foo
cp:
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo:
name too long (not copied)
cp:
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/fo
o/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo
/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/
foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f
oo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/foo/f...
looks like a feature to me. ;)
-B
Agreed, although it does not seem to exists on GNU/Linux since GNU's cp
is different from BSD's. The feature is present on {Net,Open,Free}BSD.It's not that a big deal, is it? Eventually, the question could be: what
should be limiting cp there? a max_path value, or... himself? I think
the former's the best.Just my 2 cents. :)
--
B+ A nation is a society united by a delusion about it's ancestry and by
common hatred of its neighbours. B; -- Dean William R. Inge
penguin's behaviour:
elachistos| cp -R foo foo
On Debian, you also end up with a directory structure consisting of
one new 'foo' directory within the original 'foo' directory, which is
contradicting the message about not being able to copy foo into
itself...$ mkdir foo
$ touch foo/bar
$ cp -R foo foo
cp: cannot copy a directory, `foo', into itself, `foo/foo'
$ ls -lR foo
foo:
total 4
-rw-r--r-- 1 ak ak 0 2007-10-19 11:14 bar
drwxr-xr-x 2 ak ak 4096 2007-10-19 11:14 foofoo/foo:
total 0
-rw-r--r-- 1 ak ak 0 2007-10-19 11:14 barAccording to SUSv3, the cp utility *may* issue a diagnostic message
when the source and target arguments are the same. IMHO we're doing
the right thing with regards to that part. I'm not sure about
recursively creating a very deep directory structure, but it's not a
problem really.Andreas
--
Andreas Kahari
Somewhere in the general Cambridge area, UK
| Bart Van Assche | Integration of SCST in the mainstream Linux kernel |
| Greg KH | [GIT PATCH] driver core patches against 2.6.24 |
| Roland McGrath | Re: Linus 2.6.23-rc1 |
| Rafael J. Wysocki | [Bug #10984] MMC print trace information when resume from suspend |
git: | |
| Gerrit Renker | [PATCH 03/37] dccp: List management for new feature negotiation |
| Corey Minyard | [PATCH 3/3] Convert the UDP hash lock to RCU |
| David Miller | [GIT]: Networking |
| David Miller | xfrm_state locking regression... |
