Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.9k stars 540 forks source link

File::Copy::move does not move when destination is hardlink to source #10009

Open p5pRT opened 14 years ago

p5pRT commented 14 years ago

Migrated from rt.perl.org#71082 (status was 'open')

Searchable as RT71082$

p5pRT commented 14 years ago

From perlbug@plan9.de

Created by perlbug@plan9.de

File​::Copy​::move silently fails to move a file if the destination path happens to be a hardlink to the same file as the source path. The effetc is that it returns success\, but both source and destination paths still exist.

The problem is likely that it uses rename but doesn't check whether rename actually does something (rename simply returns sucecss if source and destination refer to the same file).

Perl Info ``` Flags: category=library severity=low Site configuration information for perl 5.10.0: Configured by Marc Lehmann at Sat Feb 21 02:30:27 CET 2009. Summary of my perl5 (revision 5 version 10 subversion 0) configuration: Platform: osname=linux, osvers=2.6.24-etchnhalf.1-amd64, archname=amd64-linux uname='linux cerebro 2.6.24-etchnhalf.1-amd64 #1 smp mon jul 21 10:36:02 utc 2008 x86_64 gnulinux ' config_args='-Duselargefiles -Dxxxxuse64bitint -Uuse64bitall -Dusemymalloc=n -Dcc=gcc -Dccflags=-ggdb -gdwarf-2 -g3 -Dcppflags=-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include -Doptimize=-O6 -msse2 -funroll-loops -fno-strict-aliasing -Dcccdlflags=-fPIC -Dldflags=-L/opt/perl/lib -L/opt/lib -Dlibs=-ldl -lm -lcrypt -Darchname=amd64-linux -Dprefix=/opt/perl -Dprivlib=/opt/perl/lib/perl5 -Darchlib=/opt/perl/lib/perl5 -Dvendorprefix=/opt/perl -Dvendorlib=/opt/perl/lib/perl5 -Dvendorarch=/opt/perl/lib/perl5 -Dsiteprefix=/opt/perl -Dsitelib=/opt/perl/lib/perl5 -Dsitearch=/opt/perl/lib/perl5 -Dsitebin=/opt/perl/bin -Dman1dir=/opt/perl/man/man1 -Dman3dir=/opt/perl/man/man3 -Dsiteman1dir=/opt/perl/man/man1 -Dsiteman3dir=/opt/perl/man/man3 -Dman1ext=1 -Dman3ext=3 -Dpager=/usr/bin/less -Uafs -Uusesfio -Uusenm -Uuseshrplib -Dd_dosuid -Dusethreads=undef -Duse5005threads=undef -Duseithreads=undef -Dusemultiplicity=undef -Demail=perl-binary@plan9.de -Dcf_email=perl-binary@plan9.de -Dcf_by=Marc Lehmann -Dlocincpth=/opt/perl/include /opt/include -Dmyhostname=localhost -Dmultiarch=undef -Dbin=/opt/perl/bin -Dxxxusedevel -DxxxDEBUGGING -Dxxxuse_debugging_perl -Dxxxuse_debugmalloc -des' hint=recommended, useposix=true, d_sigaction=define useithreads=undef, usemultiplicity=undef useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef use64bitint=define, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='gcc', ccflags ='-ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-O6 -msse2 -funroll-loops -fno-strict-aliasing', cppflags='-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include -ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe -I/opt/include' ccversion='', gccversion='4.3.2', gccosandvers='' intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16 ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='gcc', ldflags ='-L/opt/perl/lib -L/opt/lib -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64 libs=-ldl -lm -lcrypt perllibs=-ldl -lm -lcrypt libc=/lib/libc-2.7.so, so=so, useshrplib=false, libperl=libperl.a gnulibc_version='2.7' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E' cccdlflags='-fPIC', lddlflags='-shared -O6 -msse2 -funroll-loops -fno-strict-aliasing -L/opt/perl/lib -L/opt/lib -L/usr/local/lib' Locally applied patches: http://public.activestate.com/cgi-bin/perlbrowse/p/34209 http://public.activestate.com/cgi-bin/perlbrowse/p/34507 http://www.gossamer-threads.com/lists/perl/porters/232549 embed.fnc:Perl_vcroak NULLOK @INC for perl 5.10.0: /root/src/sex /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 /opt/perl/lib/perl5 . Environment for perl 5.10.0: HOME=/root LANG (unset) LANGUAGE (unset) LC_CTYPE=en_US.UTF-8 LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/root/s2:/root/s:/opt/bin:/opt/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11/bin:/usr/games:/usr/local/bin:/usr/local/sbin:/root/pserv:. PERL5LIB=/root/src/sex PERL5_CPANPLUS_CONFIG=/root/.cpanplus/config PERLDB_OPTS=ornaments=0 PERL_ANYEVENT_DBI_TESTS=1 PERL_ANYEVENT_EDNS0=1 PERL_ANYEVENT_NET_TESTS=1 PERL_ANYEVENT_PROTOCOLS=ipv4,ipv6 PERL_ANYEVENT_STRICT=1 PERL_BADLANG (unset) PERL_UNICODE=E SHELL=/bin/bash ```
p5pRT commented 12 years ago

From @jkeenan

On Sun Dec 06 16​:58​:15 2009\, perlbug@​plan9.de wrote​:

File​::Copy​::move silently fails to move a file if the destination path happens to be a hardlink to the same file as the source path. The effetc is that it returns success\, but both source and destination paths still exist.

The problem is likely that it uses rename but doesn't check whether rename actually does something (rename simply returns sucecss if source and destination refer to the same file).

To my surprise\, I get different results on different OSes when I try to reproduce this phenomenon. In my case\, the two OSes are Linux and Darwin.

On both OSes​: ### $ cat alpha.txt $class = {   alpha => 'beta'\,   gamma => 'delta'\,   epsilon => 'zeta'\, };

$ ln -v alpha.txt tmp/beta.txt tmp/beta.txt => alpha.txt

$ cat tmp/beta.txt $class = {   alpha => 'beta'\,   gamma => 'delta'\,   epsilon => 'zeta'\, }; ###

On Linux​:

### $ perl -MFile​::Copy -e 'move "./alpha.txt" => "tmp/beta.txt" or die "Unable to move​: $!";'

$ cat alpha.txt $class = {   alpha => 'beta'\,   gamma => 'delta'\,   epsilon => 'zeta'\, };

$ cat tmp/beta.txt $class = {   alpha => 'beta'\,   gamma => 'delta'\,   epsilon => 'zeta'\, }; ###

Corroborates problem reported by original poster.

However\, on Darwin ...

### $ perl -MFile​::Copy -e 'move "./alpha.txt" => "tmp/beta.txt" or die "Unable to move​: $!";'

$ cat alpha.txt cat​: alpha.txt​: No such file or directory

$ cat tmp/beta.txt $class = {   alpha => 'beta'\,   gamma => 'delta'\,   epsilon => 'zeta'\, }; ###

... which does what I think original poster feels should happen.

Am I misunderstanding something about the problem -- or is this a genuine difference between the two OSes?

Thank you very much. Jim Keenan

p5pRT commented 12 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 12 years ago

From schmorp@schmorp.de

On Tue\, Nov 29\, 2011 at 04​:27​:53PM -0800\, James E Keenan via RT \perlbug\-followup@​perl\.org wrote​:

To my surprise\, I get different results on different OSes when I try to reproduce this phenomenon. In my case\, the two OSes are Linux and Darwin.

Just guessing\, but thats probably because linux implements posix rename() accurately\, while some versions of os x are only posix-certified and far from actually implementing it :)

The relevant posix spec section is\, as I know nowadays​:

If the old argument and the new argument resolve to the same existing file\, rename() shall return successfully and perform no other action.

that is\, if both old and new are hardlinks to the same file\, rename just does nothing\, leaving both intact\, reporting success. this is not a bug in the posix spec either\, it's really meant to act like that.

silly - one would expect rename to work on filenames.

In any case\, since rename is "just" an optimiation\, File​::Copy ought to detect that (coreutils mv does it for example\, at least when not posixly correct). Maybe unlinking the from after a successfull rename might do the trick - I'd rather not think too hard about it.

In any case\, rename returning success on a posix system does not mean the old name has been removed\, and thats likely whats happening.

--   The choice of a Deliantra\, the free code+content MORPG   -----==- _GNU_ http​://www.deliantra.net   ----==-- _ generation   ---==---(_)__ __ ____ __ Marc Lehmann   --==---/ / _ \/ // /\ \/ / schmorp@​schmorp.de   -=====/_/_//_/\_\,_/ /_/\_\