I'm not sure what File::Copy will do in case a destination filename exists: will it replace the old file, or fail to copy? I've had a good look at the source already, and it looks to me like copy might fail if the destination file exists, at least on Windows; but move will overwrite it — if only because move will try to rename, and AFAIK that always replaces an existing file. But I'm not really willing to trust that to be the case for all platforms, and I'm not even planning on trying them all out and write platform-dependant code. I've already had enough troubles with API calls that behave differently on one and the same platform, but on different types of disks (NTFS vs. FAT). So that's a dead end.
I've already developed two strategies (to avoid race conditions), for what to do if you're sure a copy will fail, and what if a copy will overwrite an existing file. I'm using a sub (details not important now) that composes a filename out of the base name, the file extension and a counter number. For example, a file "landscape.jpg" could be copied to a destination "landscape(1).jpg". And "copy" is used as an example here, it could be any of File::Copy's copy/move.
use Fcntl qw(O_CREAT O_EXCL O_WRONLY); my $i; while(1) { my $dest = compose_name($base, $ext, $i++); if(sysopen my $fh, $dest, O_CREAT | O_EXCL | O_WRONLY) { close $fh; copy $source, $dest; last; } }
An extra caveat is that I've read that O_EXCL isn't reliable on NFS.
my $i; while(1) { my $dest = compose_name($base, $ext, $i++); if(copy $source, $dest) { last; } }
I don't know what case I'm in, and I'd like to use common code for copy and for move. What I need is an algorithm that works reliably for either case. I've thought of the following:
but the problem remains: how to generate a unique temporary filename without clobbering other existing files? It could be that several scripts using the same module are trying to copy similarly named files to the same disk, and thus, we have a race condition. And there's still the problem of NFS.use Fcntl qw(O_CREAT O_EXCL O_WRONLY); my $i; while(1) { my $dest = compose_name($base, $ext, $i++); if(sysopen my $fh, $dest, O_CREAT | O_EXCL | O_WRONLY) { close $fh; my $tempfile = generate_tempfilename($destdir); copy $source, $tempfile; rename $tempfile, $dest; # should replace file last; } }
So, I'm polling for ideas... how would you tackle this?
In reply to How to move/copy a file without overwriting an existing file by bart
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |