#############################################################################
#
# Apache::Session::Store::File
# Implements session object storage via flat files
# Copyright(c) 1998, 1999, 2000, 2004 Jeffrey William Baker (jwbaker@acm.org)
# Distribute under the Artistic License
#
############################################################################

package Apache::Session::Store::File;

use strict;
use Symbol;
use Fcntl;
use vars qw($VERSION);

$VERSION = '1.03';

$Apache::Session::Store::File::Directory = '/tmp';

sub new {
    my $class = shift;
    my $self;
    
    $self->{fh}     = Symbol::gensym();
    $self->{opened} = 0;
    
    return bless $self, $class;
}

sub insert {
    my $self    = shift;
    my $session = shift;
 
    my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory;

    if (-e $directory.'/'.$session->{data}->{_session_id}) {
        die "Object already exists in the data store";
    }
    
    my $file = $directory.'/'.$session->{data}->{_session_id};
    sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) ||
        die "Could not open file $file: $!";

    $self->{opened} = 1;
    
    print {$self->{fh}} $session->{serialized};
}

sub update {
    my $self    = shift;
    my $session = shift;
    
    my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory;

    if (!$self->{opened}) {
        my $file = $directory.'/'.$session->{data}->{_session_id};
        sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) ||
            die "Could not open file $file: $!";

        $self->{opened} = 1;
    }
    
    truncate($self->{fh}, 0) || die "Could not truncate file: $!";
    seek($self->{fh}, 0, 0);
    print {$self->{fh}} $session->{serialized};
}

sub materialize {
    my $self    = shift;
    my $session = shift;
    
    my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory;
    
    my $file = $directory.'/'.$session->{data}->{_session_id};
    if (-e $file) {
        if (!$self->{opened}) {
            sysopen ($self->{fh}, $file, O_RDWR|O_CREAT) ||
                die "Could not open file $file: $!";

            $self->{opened} = 1;
        }
        else {
            seek($self->{fh}, 0, 0) || die "Could not seek file: $!";
        }
        
        my $fh = $self->{fh};
        while (<$fh>) {
            $session->{serialized} .= $_;
        }
    }
    else {
        die "Object does not exist in the data store";
    }
}    

sub remove {
    my $self    = shift;
    my $session = shift;
        
    my $directory = $session->{args}->{Directory} || $Apache::Session::Store::File::Directory;

    if ($self->{opened}) {
        CORE::close $self->{fh};
        $self->{opened} = 0;
    }

    my $file = $directory.'/'.$session->{data}->{_session_id};
    if (-e $file) {
        unlink ($file) ||
            die "Could not remove file $file: $!";
    }
    else {
        die "Object does not exist in the data store";
    }
}

sub close {
    my $self = shift;
    
    if ($self->{opened}) {
        CORE::close $self->{fh};
        $self->{opened} = 0;
    }
}

sub DESTROY {
    my $self = shift;
    
    if ($self->{opened}) {    
        CORE::close $self->{fh};
    }
}

1;

=pod

=head1 NAME

Apache::Session::Store::File - Store persistent data on the filesystem

=head1 SYNOPSIS


 use Apache::Session::Store::File;
 
 my $store = new Apache::Session::Store::File;
 
 $store->insert($ref);
 $store->update($ref);
 $store->materialize($ref);
 $store->remove($ref);

=head1 DESCRIPTION

This module fulfills the storage interface of Apache::Session.  The serialized
objects are stored in files on your filesystem.

=head1 OPTIONS

This module requires one argument in the usual Apache::Session style.  The
name of the option is Directory, and the value is the full path of the 
directory where you wish to place the files.  Example

 tie %s, 'Apache::Session::File', undef,
    {Directory => '/tmp/sessions'};

=head1 NOTES

All session objects are stored in the same directory.  Some filesystems, such
as Linux's ext2fs, have O(n) performance where n is the number of files in a
directory.  Other filesystems, like Sun's UFS, and Linux's reiserfs, do not
have this problem.  You should consider your filesystem's performance before
using this module to store many objects.

=head1 AUTHOR

This module was written by Jeffrey William Baker <jwbaker@acm.org>.

=head1 SEE ALSO

L<Apache::Session>
