<?xml version="1.0" encoding="windows-1252"?>
<node id="1013642" title="'Anonymous' copy via file handle fails" created="2013-01-16 15:34:42" updated="2013-01-16 15:34:42">
<type id="115">
perlquestion</type>
<author id="989451">
Monk::Thomas</author>
<data>
<field name="doctext">
&lt;p&gt;(This is part of a larger program. I stripped the code example down.)&lt;/p&gt;

&lt;p&gt;I'd like to get a file from somewhere (HTTP, SCP, FTP, local file) and make a local copy via fetch(), pass the file descriptor around, modify the content and later on write the file content to one or more other files.&lt;/p&gt;

&lt;p&gt;Alternative a) It would be easy to do this via actual file names but I would like to use open filehandles without an actual filename. This way I wouldn't have to worry about someone tampering with my data while I'm working on it.&lt;/p&gt;

&lt;p&gt;Alternative b) I don't want to slurp the file content into main memory.&lt;/p&gt;

&lt;p&gt;Script output:&lt;/p&gt;

&lt;pre&gt;
[FETCH] The file '/etc/services' has inode 2105201 and size 19398
[FETCH] The file 'GLOB(0x10c7c78)' has inode 142159 and size 19398
[STORE] The file 'GLOB(0x10c7c78)' has inode 142159 and size 19398
[STORE] The file '/tmp/services.d1JH' has inode 142160 and size 0
[STORE] Copying filehandle tmp1 (GLOB(0x10c7c78)) to tmp2 (/tmp/services.d1JH) file.
[STORE] The file 'GLOB(0x10c7c78)' has inode 142159 and size 19398
[STORE] The file '/tmp/services.d1JH' has inode 142160 and size 0
-rw------- 1 thomas thomas 0 Jan 16 21:15 /tmp/services_copy
&lt;/pre&gt;

&lt;p&gt;As you can see, the store() function seems to receive the correct data to the file object, but copy does not actually copy the file. I seriously scratched my head on this, but so far no enlightenment has occured. Buffering issue? Copy not happy with the GLOBs? Something totally different?&lt;/p&gt;

&lt;p&gt;Time to confess my non-knowledge and ask a senior monk. Hopefully I get something more then just a koan. ;)&lt;/p&gt;

&lt;code&gt;
#!/usr/bin/env perl

use strict;
use warnings;

use 5.010_001;

use English qw( -no_match_vars );    # avoid regex performance penalty
use File::Copy;
use File::Temp qw(tempfile);
use Readonly;

Readonly my $STAT_INODE =&gt; '1';
Readonly my $STAT_SIZE  =&gt; '7';

my $tmp_fh = fetch();
store($tmp_fh);
exit 0;

sub fetch {
	my $src_file = '/etc/services';
	show_filestats('FETCH', $src_file);

	my ( $tmp1_fh, $tmp1_filename ) = tempfile();
	unlink $tmp1_filename; # 

	copy $src_file, $tmp1_fh
		or die "$ERRNO\n";
	show_filestats('FETCH', $tmp1_fh);

	return $tmp1_fh;
}

sub store {
	my $tmp1_fh = shift;
	my $tmp2_file = File::Temp-&gt;new( TEMPLATE =&gt; '/tmp/services.XXXX', UNLINK =&gt; 0 );
	my $dst_file = '/tmp/services_copy';

	show_filestats('STORE', $tmp1_fh);
	show_filestats('STORE', $tmp2_file);

	print "[STORE] Copying filehandle tmp1 ($tmp1_fh) to tmp2 ($tmp2_file) file.\n"
	  or croak();

	copy $tmp1_fh, $tmp2_file
		or die "E: $ERRNO\n";

	show_filestats('STORE', $tmp1_fh);
	show_filestats('STORE', $tmp2_file);

	# apply permissions and ACLs
	rename $tmp2_file, $dst_file
	  or die "E: $ERRNO\n";
}

sub show_filestats {
	my $id = shift;
	my $fh = shift;

	my ( $inode, $size ) = ( stat $fh )[ $STAT_INODE, $STAT_SIZE ];
	print "[$id] The file '$fh' has inode $inode and size $size\n"
	  or croak();

	return;
}
&lt;/code&gt;</field>
</data>
</node>
