Programming bugs typically occur for very precise reasons. Therefore, it is important for code samples to be precise, and to actually duplicate the behavior that is being seen. Your code sample will not compile because you didn't quote your file paths. Because of this mistake, we must be left to wonder what else, in your code example, fails to demonstrate the actual bug you are seeing. It's often difficult to decipher what mistake you're making if the code sample you provide isn't useful, or has errors unrelated to what you're asking about.
I can say that this works as intended:
$ touch foo # Create a file.
$ rm -rf foobar # Assure that the foobar directory doesn't exist.
$ perl -MFile::Copy=move -E 'move("foo", "foobar/foo") or die $!' # T
+est a move into a directory that doesn't exist.
# No such file or directory at -e line 1.
ls foo # Assure the original file still exists.
# foo
The file still exists after the failed move.
| [reply] [d/l] |
Yes, and this can also lead to an "XY error" where you think that you're seeing one behavior but, because you don't realize that you made a possibly-unrelated mistake, are completely misled about what is actually going wrong. BIG time-waster.
| [reply] |
This is perl 5.32 on fedora 32
Using an older version of File::Copy (2.30) my SSCCE shows that the source file still exists. Perhaps try running this and see what happens?
use strict;
use warnings;
use Test::More tests => 4;
use File::Copy 'move';
# Create a file
my $src = '/tmp/foo.txt';
my $destdir = '/flurble';
open my $tmp, '>', $src or die $!;
print $tmp "Hello, world!\n";
close $tmp;
ok -e $src, "Source file $src exists";
ok ! -d $destdir, "Destination directory $destdir does not exist";
ok ! move ($src, "$destdir/bar.txt"), 'Move fails as expected';
ok -e $src, "Source file $src still exists";
Update: fixed open statement to use the $src variable.
| [reply] [d/l] [select] |
Are you doing this over NFS, Samba, or some other networked file system?
I recommend making a full copy, then explicitly deleting the source file only once you've verified the file has been copied to your satisfaction. | [reply] [d/l] |
I recommend making a full copy, then explicitly deleting the source file only once you've verified the file has been copied to your satisfaction.
That sounds like a good idea. Actually, someone already had exactly that idea. Quoting File::Copy:
move
[...]
If possible, move() will simply rename the file. Otherwise, it copies the file to the new location and deletes the original. If an error occurs during this copy-and-delete process, you may be left with a (possibly partial) copy of the file under the destination name.
Looking at the source, File::Copy::_move(), the backend for File::Copy::move() and File::Copy::mv(), tries really hard to detect and work around OS-specific quirks. On OS/2 and VMS, an existing destination file is deleted first. Then, rename() is tried. If that fails, the fallback code takes over (copy and delete). And only if that fails, the new copy is removed if possible:
# note: $fallback is \&File::Copy::copy() or \&File::Copy::cp()
return 1 if rename $from, $to;
# Did rename return an error even though it succeeded, because $to
# is on a remote NFS file system, and NFS lost the server's ack?
return 1 if defined($fromsz) && !-e $from && # $from dis
+appeared
(($tosz2,$tomt2) = (stat($to))[7,9]) && # $to's the
+re
((!defined $tosz1) || # not befo
+re or
($tosz1 != $tosz2 or $tomt1 != $tomt2)) && # was
+ changed
$tosz2 == $fromsz; # it's all
+there
($tosz1,$tomt1) = (stat($to))[7,9]; # just in case rename did som
+ething
{
local $@;
eval {
local $SIG{__DIE__};
$fallback->($from,$to) or die;
my($atime, $mtime) = (stat($from))[8,9];
utime($atime, $mtime, $to);
unlink($from) or die;
};
return 1 unless $@;
}
($sts,$ossts) = ($! + 0, $^E + 0);
($tosz2,$tomt2) = ((stat($to))[7,9],0,0) if defined $tomt1;
unlink($to) if !defined($tomt1) or $tomt1 != $tomt2 or $tosz1 != $
+tosz2;
($!,$^E) = ($sts,$ossts);
return 0;
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
Much apologies to all, I was incorrect
The deletion was happening in an unrelated piece of code, which had been triggered by a change elsewhere in the code
| [reply] |
| [reply] |