Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Using the file handle created by File::Temp to set specific file permissions

by mldvx4 (Friar)
on Dec 10, 2021 at 12:13 UTC ( [id://11139540]=perlquestion: print w/replies, xml ) Need Help??

mldvx4 has asked for the wisdom of the Perl Monks concerning the following question:

I plan to read the file permissions from an existing file, create a temporary file with the same permissions, rename the existing file to a backup name, and then give the temporary file the name of the original. In basic shell this would have been somewhat straight forward with mktemp(1), chmod(1), and mv(1) However, reading the manual page for File::Temp there seems to be no option to set the file permissions and it has a warning about working via the file handle instead of the file name:

For maximum security, endeavour always to avoid ever looking at, touching, or even imputing the existence of the filename. You do not know that that filename is connected to the same file as the handle you have, and attempts to check this can only trigger more race conditions. It's far more secure to use the filehandle alone and dispense with the filename altogether.

How can I use the file handle and still set the permissions and then rename the file after writing to it? Fcntl is mentioned but after looking at the manual page, it seems rather opaque.

Replies are listed 'Best First'.
Re: Using the file handle created by File::Temp to set specific file permissions
by dave_the_m (Monsignor) on Dec 10, 2021 at 17:54 UTC
    As the documentation for perl's chmod() function says, on platforms that support it, you can pass a file handle rather than a filename to chmod().

    Dave.

      Thanks. I had missed that. Both chmod and chown can process file handles.

Re: Using the file handle created by File::Temp to set specific file permissions
by choroba (Cardinal) on Dec 10, 2021 at 13:27 UTC
    Once you run chmod in a shell with more permissive setting than =u+rw/0600 (which is the permissions File::Temp uses when creating a temp file), the temp file is insecure. So if you're OK with that approach, ignore the "maximum security" recommendation and follow the same steps in Perl, i.e. use the filename. You can't rename a filehandle.

    Fcntl is mentioned for "passing it [the file descriptor] to another process". You don't need it for chmod or rename.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Thanks. Looking further into this, File::Copy can work with file handles and even has a "move" function.

Re: Using the file handle created by File::Temp to set specific file permissions
by eyepopslikeamosquito (Archbishop) on Dec 11, 2021 at 07:25 UTC

    If your goal is to safely edit a file, without suffering nasty race conditions, the straightforward solution I concocted back in 2003 (and am still happy with) is to simply write a new file on the same file system ... and then use (atomic) rename to clobber the original file - but only after the new file has been successfully written. This is described in detail at:

      Interesting sample. I've tried the following so far, but will have to redo my location for the temporary file based on the location of the destination. That is so it will be on the same partition as the file it is replacing. Otherwise, I get the error, "Could not rename temporary file handle: Invalid cross-device link".

      #!/usr/bin/perl use File::Temp; use strict; use warnings; my @data = qw/a b c d e f g h i j k l m n o p/; my $file="/tmp/foo.txt"; my (undef, undef, $mode, undef, $uid, $gid) = stat("$file"); $mode = sprintf( "%04o", $mode & 07777); my $tmp = File::Temp->new( TEMPLATE => 'tempXXXXX', DIR => '/tmp', SUFFIX => '.foobar', UNLINK => 1 ); chmod(oct($mode), $tmp) or die("Could not change tempfile to mode $mode.\n"); for my $d (@data) { print $tmp $d,"\n"; } rename($file, "$file.orig") or die("Could not rename original file, '$file': $!\n"); rename($tmp, "$file") or die("Could not rename temporary file handle: $!\n"); close($tmp); exit(0);

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11139540]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2024-04-24 17:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found