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};
85 sub get_version_count {
86 my ($self, %params) = @_;
87 die "no dbfile" unless $params{dbfile};
88 return $params{dbfile}->backend_data * 1;
92 my ($self, %params) = @_;
93 die "no dbfile" unless $params{dbfile};
94 die "unknown version" if $params{version} &&
95 ($params{version} < 0 || $params{version} > $params{dbfile}->backend_data);
96 my $path = $self->_filesystem_path($params{dbfile}, $params{version});
98 die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
100 my @st = stat($path);
101 my $dt = DateTime->from_epoch(epoch => $st[9])->clone();
106 my ($self, %params) = @_;
107 die "no dbfile" unless $params{dbfile};
108 my $path = $self->_filesystem_path($params{dbfile},$params{version});
109 die "no file in backend get_filepath" if !-f $path;
114 my ($self, %params) = @_;
115 my $path = $self->get_filepath(%params);
116 return "" unless $path;
117 my $contents = File::Slurp::read_file($path);
122 return 0 unless $::instance_conf->get_doc_files;
123 return 0 unless $::lx_office_conf{paths}->{document_path};
124 return 0 unless -d $::lx_office_conf{paths}->{document_path};
128 sub sync_from_backend {
129 my ($self, %params) = @_;
130 my @query = (file_type => $params{file_type});
131 push @query, (file_name => $params{file_name}) if $params{file_name};
132 push @query, (mime_type => $params{mime_type}) if $params{mime_type};
133 push @query, (source => $params{source}) if $params{source};
135 my $sortby = $params{sort_by} || 'itime DESC,file_name ASC';
137 my @files = @{ SL::DB::Manager::File->get_all(query => [@query], sort_by => $sortby) };
139 $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $_->id." version=".$_->backend_data);
140 my $newversion = $_->backend_data;
141 for my $version ( reverse 1 .. $_->backend_data ) {
142 my $path = $self->_filesystem_path($_, $version);
143 $main::lxdebug->message(LXDebug->DEBUG2(), "path=".$path." exists=".( -f $path?1:0));
145 $newversion = $version - 1;
147 $main::lxdebug->message(LXDebug->DEBUG2(), "newversion=".$newversion." version=".$_->backend_data);
148 if ( $newversion < $_->backend_data ) {
149 $_->backend_data($newversion);
150 $_->save if $newversion > 0;
151 $_->delete if $newversion <= 0;
161 sub _filesystem_path {
162 my ($self, $dbfile, $version) = @_;
164 die "No files backend enabled" unless $::instance_conf->get_doc_files || $::lx_office_conf{paths}->{document_path};
166 # use filesystem with depth 3
167 $version = $dbfile->backend_data if !$version || $version < 1 || $version > $dbfile->backend_data;
168 my $iddir = sprintf("%04d", $dbfile->id % 1000);
169 my $path = File::Spec->catdir($::lx_office_conf{paths}->{document_path}, $::auth->client->{id}, $iddir, $dbfile->id);
171 File::Path::make_path($path, { chmod => 0770 });
173 return $path if !$version;
174 return File::Spec->catdir($path, $dbfile->id . '_' . $version);
187 SL::File::Backend::Filesystem - Filesystem class for file storage backend
191 See the synopsis of L<SL::File::Backend>.
195 This specific storage backend use a Filesystem which is only accessed by this interface.
196 This is the big difference to the Webdav backend where the files can be accessed without the control of that backend.
197 This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories
198 to store the files not to flat in the filesystem. In this Subdirectories for each file an additional subdirectory exists
199 for the versions of this file.
201 The Versioning is done via a Versionnumber which is incremented by one for each version.
202 So the Version 2 of the file with the database id 4 is stored as path {root}/0004/4/4_2.
207 See methods of L<SL::File::Backend>.
215 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>