|
1 |
package SL::File::Backend::Filesystem;
|
|
2 |
|
|
3 |
use strict;
|
|
4 |
|
|
5 |
use parent qw(SL::File::Backend);
|
|
6 |
use SL::DB::File;
|
|
7 |
use File::Copy;
|
|
8 |
use File::Slurp;
|
|
9 |
use File::Path qw(make_path);
|
|
10 |
|
|
11 |
#
|
|
12 |
# public methods
|
|
13 |
#
|
|
14 |
|
|
15 |
sub delete {
|
|
16 |
my ($self, %params) = @_;
|
|
17 |
$main::lxdebug->message(LXDebug->DEBUG2(), "del in backend " . $self . " file " . $params{dbfile});
|
|
18 |
$main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . ($params{dbfile}->id * 1));
|
|
19 |
die "no dbfile" unless $params{dbfile};
|
|
20 |
my $backend_data = $params{dbfile}->backend_data;
|
|
21 |
$backend_data = 0 if $params{last};
|
|
22 |
$backend_data = $params{dbfile}->backend_data-1 if $params{all_but_notlast};
|
|
23 |
|
|
24 |
if ($backend_data > 0 ) {
|
|
25 |
$main::lxdebug->message(LXDebug->DEBUG2(), "backend_data=" .$backend_data);
|
|
26 |
for my $version ( 1..$backend_data) {
|
|
27 |
my $file_path = $self->_filesystem_path($params{dbfile},$version);
|
|
28 |
$main::lxdebug->message(LXDebug->DEBUG2(), "unlink " .$file_path);
|
|
29 |
unlink($file_path);
|
|
30 |
}
|
|
31 |
if ($params{all_but_notlast}) {
|
|
32 |
my $from = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
|
|
33 |
my $to = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
|
|
34 |
die "file not exists" unless -f $from;
|
|
35 |
rename($from,$to);
|
|
36 |
$params{dbfile}->backend_data(1);
|
|
37 |
} else {
|
|
38 |
$params{dbfile}->backend_data(0);
|
|
39 |
my $dir_path = $self->_filesystem_path($params{dbfile});
|
|
40 |
rmdir($dir_path);
|
|
41 |
$main::lxdebug->message(LXDebug->DEBUG2(), "unlink " .$dir_path);
|
|
42 |
}
|
|
43 |
} else {
|
|
44 |
my $file_path = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
|
|
45 |
die "file not exists" unless -f $file_path;
|
|
46 |
unlink($file_path);
|
|
47 |
$params{dbfile}->backend_data($params{dbfile}->backend_data-1);
|
|
48 |
}
|
|
49 |
}
|
|
50 |
|
|
51 |
sub rename {
|
|
52 |
}
|
|
53 |
|
|
54 |
sub save {
|
|
55 |
my ($self, %params) = @_;
|
|
56 |
die 'dbfile not exists' unless $params{dbfile};
|
|
57 |
$main::lxdebug->message(LXDebug->DEBUG2(), "in backend " . $self . " file " . $params{dbfile});
|
|
58 |
$main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $params{dbfile}->id . " path=" . $params{file_path});
|
|
59 |
my $dbfile = $params{dbfile};
|
|
60 |
die 'no file contents' unless $params{file_path} || $params{file_contents};
|
|
61 |
$dbfile->backend_data(0) unless $dbfile->backend_data;
|
|
62 |
$dbfile->backend_data($dbfile->backend_data*1+1);
|
|
63 |
$dbfile->save->load;
|
|
64 |
|
|
65 |
my $tofile = $self->_filesystem_path($dbfile);
|
|
66 |
$main::lxdebug->message(LXDebug->DEBUG2(), "topath=" . $tofile . " from=" . $params{file_path});
|
|
67 |
if ($params{file_path} && -f $params{file_path}) {
|
|
68 |
File::Copy::copy($params{file_path}, $tofile);
|
|
69 |
}
|
|
70 |
elsif ($params{file_contents}) {
|
|
71 |
open(OUT, "> " . $tofile);
|
|
72 |
print OUT $params{file_contents};
|
|
73 |
close(OUT);
|
|
74 |
}
|
|
75 |
return 1;
|
|
76 |
}
|
|
77 |
|
|
78 |
sub get_version_count {
|
|
79 |
my ($self, %params) = @_;
|
|
80 |
die "no dbfile" unless $params{dbfile};
|
|
81 |
return $params{dbfile}->backend_data * 1;
|
|
82 |
}
|
|
83 |
|
|
84 |
sub get_mtime {
|
|
85 |
my ($self, %params) = @_;
|
|
86 |
die "no dbfile" unless $params{dbfile};
|
|
87 |
$main::lxdebug->message(LXDebug->DEBUG2(), "version=" .$params{version});
|
|
88 |
die "unknown version" if $params{version} &&
|
|
89 |
($params{version} < 0 || $params{version} > $params{dbfile}->backend_data) ;
|
|
90 |
my $path = $self->_filesystem_path($params{dbfile},$params{version});
|
|
91 |
die "no file found in backend" if !-f $path;
|
|
92 |
my @st = stat($path);
|
|
93 |
my $dt = DateTime->from_epoch(epoch => $st[9])->clone();
|
|
94 |
$main::lxdebug->message(LXDebug->DEBUG2(), "dt=" .$dt);
|
|
95 |
return $dt;
|
|
96 |
}
|
|
97 |
|
|
98 |
sub get_filepath {
|
|
99 |
my ($self, %params) = @_;
|
|
100 |
die "no dbfile" unless $params{dbfile};
|
|
101 |
my $path = $self->_filesystem_path($params{dbfile},$params{version});
|
|
102 |
die "no file" if !-f $path;
|
|
103 |
return $path;
|
|
104 |
}
|
|
105 |
|
|
106 |
sub get_content {
|
|
107 |
my ($self, %params) = @_;
|
|
108 |
my $path = $self->get_filepath(%params);
|
|
109 |
return "" unless $path;
|
|
110 |
my $contents = File::Slurp::read_file($path);
|
|
111 |
return \$contents;
|
|
112 |
}
|
|
113 |
|
|
114 |
sub enabled {
|
|
115 |
return 0 unless $::instance_conf->get_doc_files || $::instance_conf->get_doc_files_rootpath;
|
|
116 |
$main::lxdebug->message(LXDebug->DEBUG2(), "root path=" . $::instance_conf->get_doc_files_rootpath . " isdir=" .( -d $::instance_conf->get_doc_files_rootpath?"YES":"NO"));
|
|
117 |
return 0 unless -d $::instance_conf->get_doc_files_rootpath;
|
|
118 |
return 1;
|
|
119 |
}
|
|
120 |
|
|
121 |
|
|
122 |
#
|
|
123 |
# internals
|
|
124 |
#
|
|
125 |
|
|
126 |
sub _filesystem_path {
|
|
127 |
my ($self, $dbfile, $version) = @_;
|
|
128 |
|
|
129 |
die "No files backend enabled" unless $::instance_conf->get_doc_files || $::instance_conf->get_doc_files_rootpath;
|
|
130 |
|
|
131 |
# use filesystem with depth 3
|
|
132 |
$version = $dbfile->backend_data if !$version || $version < 1 || $version > $dbfile->backend_data;
|
|
133 |
my $iddir = sprintf("%04d", $dbfile->id % 1000);
|
|
134 |
my $path = File::Spec->catdir($::instance_conf->get_doc_files_rootpath, $iddir, $dbfile->id);
|
|
135 |
$main::lxdebug->message(LXDebug->DEBUG2(), "file path=" .$path." id=" .$dbfile->id." version=".$version." basename=".$dbfile->id . '_' . $version);
|
|
136 |
if (!-d $path) {
|
|
137 |
File::Path::make_path($path, { chmod => 0770 });
|
|
138 |
}
|
|
139 |
return $path if !$version;
|
|
140 |
return File::Spec->catdir($path, $dbfile->id . '_' . $version);
|
|
141 |
}
|
|
142 |
|
|
143 |
1;
|
|
144 |
|
|
145 |
__END__
|
|
146 |
|
|
147 |
=pod
|
|
148 |
|
|
149 |
=encoding utf8
|
|
150 |
|
|
151 |
=head1 NAME
|
|
152 |
|
|
153 |
SL::File::Backend::Filesystem - Filesystem class for file storage backend
|
|
154 |
|
|
155 |
=head1 SYNOPSIS
|
|
156 |
|
|
157 |
See the synopsis of L<SL::File::Backend>.
|
|
158 |
|
|
159 |
=head1 OVERVIEW
|
|
160 |
|
|
161 |
This specific storage backend use a Filesystem which is only accessed by this interface.
|
|
162 |
This is the big difference to the Webdav backend where the files can be accessed without the control of that backend.
|
|
163 |
This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories
|
|
164 |
to store the files not to flat in the filesystem. In this Subdirectories for each file an additional subdirectory exists
|
|
165 |
for the versions of this file.
|
|
166 |
|
|
167 |
The Versioning is done via a Versionnumber which is incremented by one for each version.
|
|
168 |
So the Version 2 of the file with the database id 4 is stored as path {root}/0004/4/4_2.
|
|
169 |
|
|
170 |
|
|
171 |
=head1 METHODS
|
|
172 |
|
|
173 |
See methods of L<SL::File::Backend>.
|
|
174 |
|
|
175 |
=head1 SEE ALSO
|
|
176 |
|
|
177 |
L<SL::File::Backend>
|
|
178 |
|
|
179 |
=head1 AUTHOR
|
|
180 |
|
|
181 |
Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
|
|
182 |
|
|
183 |
=cut
|
|
184 |
|
|
185 |
|
Dateimanagement: Backend "Filesystem"
mit test