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});
 
 112   die "no file in backend get_filepath" if !-f $path;
 
 117   my ($self, %params) = @_;
 
 118   my $path = $self->get_filepath(%params);
 
 119   return "" unless $path;
 
 120   my $contents = File::Slurp::read_file($path);
 
 125   return 0 unless $::instance_conf->get_doc_files;
 
 126   return 0 unless $::lx_office_conf{paths}->{document_path};
 
 127   return 0 unless -d $::lx_office_conf{paths}->{document_path};
 
 131 sub sync_from_backend {
 
 132   my ($self, %params) = @_;
 
 133   my @query = (file_type => $params{file_type});
 
 134   push @query, (file_name => $params{file_name}) if $params{file_name};
 
 135   push @query, (mime_type => $params{mime_type}) if $params{mime_type};
 
 136   push @query, (source    => $params{source})    if $params{source};
 
 138   my $sortby = $params{sort_by} || 'itime DESC,file_name ASC';
 
 140   my @files = @{ SL::DB::Manager::File->get_all(query => [@query], sort_by => $sortby) };
 
 142     $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $_->id." version=".$_->backend_data);
 
 143     my $newversion = $_->backend_data;
 
 144     for my $version ( reverse 1 .. $_->backend_data ) {
 
 145       my $path = $self->_filesystem_path($_, $version);
 
 146       $main::lxdebug->message(LXDebug->DEBUG2(), "path=".$path." exists=".( -f $path?1:0));
 
 148       $newversion = $version - 1;
 
 150     $main::lxdebug->message(LXDebug->DEBUG2(), "newversion=".$newversion." version=".$_->backend_data);
 
 151     if ( $newversion < $_->backend_data ) {
 
 152       $_->backend_data($newversion);
 
 153       $_->save   if $newversion >  0;
 
 154       $_->delete if $newversion <= 0;
 
 164 sub _filesystem_path {
 
 165   my ($self, $dbfile, $version) = @_;
 
 167   die "No files backend enabled" unless $::instance_conf->get_doc_files || $::lx_office_conf{paths}->{document_path};
 
 169   # use filesystem with depth 3
 
 170   $version    = $dbfile->backend_data if !$version || $version < 1 || $version > $dbfile->backend_data;
 
 171   my $iddir   = sprintf("%04d", $dbfile->id % 1000);
 
 172   my $path    = File::Spec->catdir($::lx_office_conf{paths}->{document_path}, $::auth->client->{id}, $iddir, $dbfile->id);
 
 174     File::Path::make_path($path, { chmod => 0770 });
 
 176   return $path if !$version;
 
 177   return File::Spec->catdir($path, $dbfile->id . '_' . $version);
 
 190 SL::File::Backend::Filesystem  - Filesystem class for file storage backend
 
 194 See the synopsis of L<SL::File::Backend>.
 
 198 This specific storage backend use a Filesystem which is only accessed by this interface.
 
 199 This is the big difference to the Webdav backend where the files can be accessed without the control of that backend.
 
 200 This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories
 
 201 to store the files not to flat in the filesystem. In this Subdirectories for each file an additional subdirectory exists
 
 202 for the versions of this file.
 
 204 The Versioning is done via a Versionnumber which is incremented by one for each version.
 
 205 So the Version 2 of the file with the database id 4 is stored as path {root}/0004/4/4_2.
 
 210 See methods of L<SL::File::Backend>.
 
 218 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>