diff options
Diffstat (limited to 'qooxdoo/source/perl/CGI/Session/Driver/file.pm')
-rw-r--r-- | qooxdoo/source/perl/CGI/Session/Driver/file.pm | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/qooxdoo/source/perl/CGI/Session/Driver/file.pm b/qooxdoo/source/perl/CGI/Session/Driver/file.pm new file mode 100644 index 0000000..f25dfea --- /dev/null +++ b/qooxdoo/source/perl/CGI/Session/Driver/file.pm @@ -0,0 +1,217 @@ +package CGI::Session::Driver::file; + +# $Id: file.pm 351 2006-11-24 14:16:50Z markstos $ + +use strict; + +use Carp; +use File::Spec; +use Fcntl qw( :DEFAULT :flock :mode ); +use CGI::Session::Driver; +use vars qw( $FileName $NoFlock $UMask $NO_FOLLOW ); + +BEGIN { + # keep historical behavior + + no strict 'refs'; + + *FileName = \$CGI::Session::File::FileName; +} + +@CGI::Session::Driver::file::ISA = ( "CGI::Session::Driver" ); +$CGI::Session::Driver::file::VERSION = "4.20"; +$FileName = "cgisess_%s"; +$NoFlock = 0; +$UMask = 0660; +$NO_FOLLOW = eval { O_NOFOLLOW } || 0; + +sub init { + my $self = shift; + $self->{Directory} ||= File::Spec->tmpdir(); + + unless ( -d $self->{Directory} ) { + require File::Path; + unless ( File::Path::mkpath($self->{Directory}) ) { + return $self->set_error( "init(): couldn't create directory path: $!" ); + } + } + + $self->{NoFlock} = $NoFlock unless exists $self->{NoFlock}; + $self->{UMask} = $UMask unless exists $self->{UMask}; + + return 1; +} + +sub _file { + my ($self,$sid) = @_; + return File::Spec->catfile($self->{Directory}, sprintf( $FileName, $sid )); +} + +sub retrieve { + my $self = shift; + my ($sid) = @_; + + my $path = $self->_file($sid); + + return 0 unless -e $path; + + # make certain our filehandle goes away when we fall out of scope + local *FH; + + if (-l $path) { + unlink($path) or + return $self->set_error("retrieve(): '$path' appears to be a symlink and I couldn't remove it: $!"); + return 0; # we deleted this so we have no hope of getting back anything + } + sysopen(FH, $path, O_RDONLY | $NO_FOLLOW ) || return $self->set_error( "retrieve(): couldn't open '$path': $!" ); + + $self->{NoFlock} || flock(FH, LOCK_SH) or return $self->set_error( "retrieve(): couldn't lock '$path': $!" ); + + my $rv = ""; + while ( <FH> ) { + $rv .= $_; + } + close(FH); + return $rv; +} + + + +sub store { + my $self = shift; + my ($sid, $datastr) = @_; + + my $path = $self->_file($sid); + + # make certain our filehandle goes away when we fall out of scope + local *FH; + + my $mode = O_WRONLY|$NO_FOLLOW; + + # kill symlinks when we spot them + if (-l $path) { + unlink($path) or + return $self->set_error("store(): '$path' appears to be a symlink and I couldn't remove it: $!"); + } + + $mode = O_RDWR|O_CREAT|O_EXCL unless -e $path; + + sysopen(FH, $path, $mode, $self->{UMask}) or return $self->set_error( "store(): couldn't open '$path': $!" ); + + # sanity check to make certain we're still ok + if (-l $path) { + return $self->set_error("store(): '$path' is a symlink, check for malicious processes"); + } + + # prevent race condition (RT#17949) + $self->{NoFlock} || flock(FH, LOCK_EX) or return $self->set_error( "store(): couldn't lock '$path': $!" ); + truncate(FH, 0) or return $self->set_error( "store(): couldn't truncate '$path': $!" ); + + print FH $datastr; + close(FH) or return $self->set_error( "store(): couldn't close '$path': $!" ); + return 1; +} + + +sub remove { + my $self = shift; + my ($sid) = @_; + + my $directory = $self->{Directory}; + my $file = sprintf( $FileName, $sid ); + my $path = File::Spec->catfile($directory, $file); + unlink($path) or return $self->set_error( "remove(): couldn't unlink '$path': $!" ); + return 1; +} + + +sub traverse { + my $self = shift; + my ($coderef) = @_; + + unless ( $coderef && ref($coderef) && (ref $coderef eq 'CODE') ) { + croak "traverse(): usage error"; + } + + opendir( DIRHANDLE, $self->{Directory} ) + or return $self->set_error( "traverse(): couldn't open $self->{Directory}, " . $! ); + + my $filename_pattern = $FileName; + $filename_pattern =~ s/\./\\./g; + $filename_pattern =~ s/\%s/(\.\+)/g; + while ( my $filename = readdir(DIRHANDLE) ) { + next if $filename =~ m/^\.\.?$/; + my $full_path = File::Spec->catfile($self->{Directory}, $filename); + my $mode = (stat($full_path))[2] + or return $self->set_error( "traverse(): stat failed for $full_path: " . $! ); + next if S_ISDIR($mode); + if ( $filename =~ /^$filename_pattern$/ ) { + $coderef->($1); + } + } + closedir( DIRHANDLE ); + return 1; +} + + +sub DESTROY { + my $self = shift; +} + +1; + +__END__; + +=pod + +=head1 NAME + +CGI::Session::Driver::file - Default CGI::Session driver + +=head1 SYNOPSIS + + $s = new CGI::Session(); + $s = new CGI::Session("driver:file", $sid); + $s = new CGI::Session("driver:file", $sid, {Directory=>'/tmp'}); + + +=head1 DESCRIPTION + +When CGI::Session object is created without explicitly setting I<driver>, I<file> will be assumed. +I<file> - driver will store session data in plain files, where each session will be stored in a separate +file. + +Naming conventions of session files are defined by C<$CGI::Session::Driver::file::FileName> global variable. +Default value of this variable is I<cgisess_%s>, where %s will be replaced with respective session ID. Should +you wish to set your own FileName template, do so before requesting for session object: + + $CGI::Session::Driver::file::FileName = "%s.dat"; + $s = new CGI::Session(); + +For backwards compatibility with 3.x, you can also use the variable name +C<$CGI::Session::File::FileName>, which will override the one above. + +=head2 DRIVER ARGUMENTS + +If you wish to specify a session directory, use the B<Directory> option, which denotes location of the directory +where session ids are to be kept. If B<Directory> is not set, defaults to whatever File::Spec->tmpdir() returns. +So all the three lines in the SYNOPSIS section of this manual produce the same result on a UNIX machine. + +If specified B<Directory> does not exist, all necessary directory hierarchy will be created. + +By default, sessions are created with a umask of 0660. If you wish to change the umask for a session, pass +a B<UMask> option with an octal representation of the umask you would like for said session. + +=head1 NOTES + +If your OS doesn't support flock, you should understand the risks of going without locking the session files. Since +sessions tend to be used in environments where race conditions may occur due to concurrent access of files by +different processes, locking tends to be seen as a good and very necessary thing. If you still want to use this +driver but don't want flock, set C<$CGI::Session::Driver::file::NoFlock> to 1 or pass C<< NoFlock => 1 >> and this +driver will operate without locks. + +=head1 LICENSING + +For support and licensing see L<CGI::Session|CGI::Session> + +=cut |