1 package SL::File::Backend::Filesystem;
 
   5 use parent qw(SL::File::Backend);
 
   9 use File::Path qw(make_path);
 
  16   my ($self, %params) = @_;
 
  17   die "no dbfile in backend delete" unless $params{dbfile};
 
  18   my $last_version  = $params{dbfile}->backend_data;
 
  19   my $first_version = 1;
 
  20   $last_version     = 0                               if $params{last};
 
  21   $last_version     = $params{dbfile}->backend_data-1 if $params{all_but_notlast};
 
  22   $last_version     = $params{version}                if $params{version};
 
  23   $first_version    = $params{version}                if $params{version};
 
  25   if ($last_version > 0 ) {
 
  26     for my $version ( $first_version..$last_version) {
 
  27       my $file_path = $self->_filesystem_path($params{dbfile},$version);
 
  30     if ($params{version}) {
 
  31       for my $version ( $last_version+1 .. $params{dbfile}->backend_data) {
 
  32         my $from = $self->_filesystem_path($params{dbfile},$version);
 
  33         my $to   = $self->_filesystem_path($params{dbfile},$version - 1);
 
  34         die "file not exists in backend delete" unless -f $from;
 
  37       $params{dbfile}->backend_data($params{dbfile}->backend_data-1);
 
  39     elsif ($params{all_but_notlast}) {
 
  40       my $from = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
 
  41       my $to   = $self->_filesystem_path($params{dbfile},1);
 
  42       die "file not exists in backend delete" unless -f $from;
 
  44       $params{dbfile}->backend_data(1);
 
  46       $params{dbfile}->backend_data(0);
 
  48     unless ($params{dbfile}->backend_data) {
 
  49       my $dir_path = $self->_filesystem_path($params{dbfile});
 
  53     my $file_path = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
 
  54     die "file not exists in backend delete" unless -f $file_path;
 
  56     $params{dbfile}->backend_data($params{dbfile}->backend_data-1);
 
  65   my ($self, %params) = @_;
 
  66   die 'dbfile not exists' unless $params{dbfile};
 
  67   my $dbfile = $params{dbfile};
 
  68   die 'no file contents' unless $params{file_path} || $params{file_contents};
 
  69   $dbfile->backend_data(0) unless $dbfile->backend_data;
 
  70   $dbfile->backend_data($dbfile->backend_data*1+1);
 
  73   my $tofile = $self->_filesystem_path($dbfile);
 
  74   if ($params{file_path} && -f $params{file_path}) {
 
  75     File::Copy::copy($params{file_path}, $tofile);
 
  77   elsif ($params{file_contents}) {
 
  78     open(OUT, "> " . $tofile);
 
  79     print OUT $params{file_contents};
 
  83     utime($params{mtime}, $params{mtime}, $tofile);
 
  88 sub get_version_count {
 
  89   my ($self, %params) = @_;
 
  90   die "no dbfile" unless $params{dbfile};
 
  91   return $params{dbfile}->backend_data * 1;
 
  95   my ($self, %params) = @_;
 
  96   die "no dbfile" unless $params{dbfile};
 
  97   die "unknown version" if $params{version} &&
 
  98                           ($params{version} < 0 || $params{version} > $params{dbfile}->backend_data);
 
  99   my $path = $self->_filesystem_path($params{dbfile}, $params{version});
 
 101   die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
 
 103   my @st = stat($path);
 
 104   my $dt = DateTime->from_epoch(epoch => $st[9], time_zone => $::locale->get_local_time_zone()->name, locale => $::lx_office_conf{system}->{language})->clone();
 
 109   my ($self, %params) = @_;
 
 110   die "no dbfile" unless $params{dbfile};
 
 111   my $path = $self->_filesystem_path($params{dbfile},$params{version});
 
 113   die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
 
 119   my ($self, %params) = @_;
 
 120   my $path = $self->get_filepath(%params);
 
 121   return "" unless $path;
 
 122   my $contents = File::Slurp::read_file($path);
 
 127   return 0 unless $::instance_conf->get_doc_files;
 
 128   return 0 unless $::lx_office_conf{paths}->{document_path};
 
 129   return 0 unless -d $::lx_office_conf{paths}->{document_path};
 
 133 sub sync_from_backend {
 
 134   my ($self, %params) = @_;
 
 135   my @query = (file_type => $params{file_type});
 
 136   push @query, (file_name => $params{file_name}) if $params{file_name};
 
 137   push @query, (mime_type => $params{mime_type}) if $params{mime_type};
 
 138   push @query, (source    => $params{source})    if $params{source};
 
 140   my $sortby = $params{sort_by} || 'itime DESC,file_name ASC';
 
 142   my @files = @{ SL::DB::Manager::File->get_all(query => [@query], sort_by => $sortby) };
 
 144     $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $_->id." version=".$_->backend_data);
 
 145     my $newversion = $_->backend_data;
 
 146     for my $version ( reverse 1 .. $_->backend_data ) {
 
 147       my $path = $self->_filesystem_path($_, $version);
 
 148       $main::lxdebug->message(LXDebug->DEBUG2(), "path=".$path." exists=".( -f $path?1:0));
 
 150       $newversion = $version - 1;
 
 152     $main::lxdebug->message(LXDebug->DEBUG2(), "newversion=".$newversion." version=".$_->backend_data);
 
 153     if ( $newversion < $_->backend_data ) {
 
 154       $_->backend_data($newversion);
 
 155       $_->save   if $newversion >  0;
 
 156       $_->delete if $newversion <= 0;
 
 166 sub _filesystem_path {
 
 167   my ($self, $dbfile, $version) = @_;
 
 169   die "No files backend enabled" unless $::instance_conf->get_doc_files || $::lx_office_conf{paths}->{document_path};
 
 171   # use filesystem with depth 3
 
 172   $version    = $dbfile->backend_data if !$version || $version < 1 || $version > $dbfile->backend_data;
 
 173   my $iddir   = sprintf("%04d", $dbfile->id % 1000);
 
 174   my $path    = File::Spec->catdir($::lx_office_conf{paths}->{document_path}, $::auth->client->{id}, $iddir, $dbfile->id);
 
 176     File::Path::make_path($path, { chmod => 0770 });
 
 178   return $path if !$version;
 
 179   return File::Spec->catdir($path, $dbfile->id . '_' . $version);
 
 192 SL::File::Backend::Filesystem  - Filesystem class for file storage backend
 
 196 See the synopsis of L<SL::File::Backend>.
 
 200 This specific storage backend use a Filesystem which is only accessed by this interface.
 
 201 This is the big difference to the Webdav backend where the files can be accessed without the control of that backend.
 
 202 This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories
 
 203 to store the files not to flat in the filesystem. In this Subdirectories for each file an additional subdirectory exists
 
 204 for the versions of this file.
 
 206 The Versioning is done via a Versionnumber which is incremented by one for each version.
 
 207 So the Version 2 of the file with the database id 4 is stored as path {root}/0004/4/4_2.
 
 212 See methods of L<SL::File::Backend>.
 
 220 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>