5
Debconf::DbDriver::PackageDir - store database in a directory
9
package Debconf::DbDriver::PackageDir;
11
use Debconf::Log qw(:all);
13
use Fcntl qw(:DEFAULT :flock);
14
use Debconf::Iterator;
15
use base 'Debconf::DbDriver::Directory';
19
This is a debconf database driver that uses a plain text file for each
20
individual "subdirectory" of the internal tree.
22
It uses a Format module to handle reading and writing the files, so the
23
files can be of any format.
31
The directory to put the files in.
35
An optional extension to tack on the end of each filename.
39
The (octal) permissions to create the files with if they do not exist.
40
Defaults to 600, since the files could contain passwords in some
45
The Format object to use for reading and writing files.
47
In the config file, just the name of the format to use, such as '822' can
48
be specified. Default is 822.
56
use fields qw(mode _loaded);
60
On initialization, we ensure that the directory exists.
67
if (exists $this->{mode}) {
68
# Convert user input to octal.
69
$this->{mode} = oct($this->{mode});
74
$this->SUPER::init(@_);
77
=head2 loadfile(filename)
79
Loads up a file by name, after checking to make sure it's not ben loaded
80
already. Omit the directory from the filename.
86
my $file=$this->{directory}."/".shift;
88
return if $this->{_loaded}->{$file};
89
$this->{_loaded}->{$file}=1;
91
debug "db $this->{name}" => "loading $file";
92
return unless -e $file;
95
open($fh, $file) or $this->error("$file: $!");
96
my @item = $this->{format}->read($fh);
98
$this->cacheadd(@item);
99
@item = $this->{format}->read($fh);
104
=head2 load(itemname)
106
After checking the cache, find the file that contains the item, then use
107
the format object to load up the item (and all other items from that file,
115
$this->loadfile($this->filename($item));
118
=head2 filename(itemname)
120
Converts the item name into a filename. (Minus the base directory.)
128
if ($item =~ m!^([^/]+)(?:/|$)!) {
129
return $1.$this->{extension};
132
$this->error("failed parsing item name \"$item\"\n");
138
This iterator is not very well written in general, as it loads up all files
139
that were not previously loaded, and then lets the super class iterate over
140
the populated cache. However, all iteration in debconf so far iterates over
141
the whole set, so it doesn't matter.
149
opendir($handle, $this->{directory}) ||
150
$this->error("opendir: $!");
152
while (my $file=readdir($handle)) {
153
next if length $this->{extension} and
154
not $file=~m/$this->{extension}/;
155
next unless -f $this->{directory}."/".$file;
156
next if $file eq '.lock' || $file =~ /-old$/;
157
$this->loadfile($file);
160
# grandparent's method; parent's does unwanted stuff
161
$this->SUPER::iterator;
164
=head2 exists(itemname)
166
Check the cache first, then check to see if a file that might contain the
167
item exists, load it, and test existence.
174
# Check the cache first.
175
my $incache=$this->Debconf::DbDriver::Cache::exists($name);
176
return $incache if (!defined $incache or $incache);
177
my $file=$this->{directory}.'/'.$this->filename($name);
178
return unless -e $file;
182
# Now check the cache again; if it exists load will have put it
184
return $this->Debconf::DbDriver::Cache::exists($name);
189
This has to break the abstraction and access the underlying cache directly.
196
return if $this->{readonly};
198
my (%files, %filecontents, %killfiles, %dirtyfiles);
199
foreach my $item (keys %{$this->{cache}}) {
200
my $file=$this->filename($item);
203
if (! defined $this->{cache}->{$item}) {
205
delete $this->{cache}->{$item};
208
push @{$filecontents{$file}}, $item;
211
if ($this->{dirty}->{$item}) {
212
$dirtyfiles{$file}++;
213
$this->{dirty}->{$item}=0;
217
foreach my $file (keys %files) {
218
if (! $filecontents{$file} && $killfiles{$file}) {
219
debug "db $this->{name}" => "removing $file";
220
my $filename=$this->{directory}."/".$file;
222
$this->error("unable to remove $filename: $!");
223
if (-e $filename."-old") {
224
unlink $filename."-old" or
225
$this->error("unable to remove $filename-old: $!");
228
elsif ($dirtyfiles{$file}) {
229
debug "db $this->{name}" => "saving $file";
230
my $filename=$this->{directory}."/".$file;
232
sysopen(my $fh, $filename."-new",
233
O_WRONLY|O_TRUNC|O_CREAT,$this->{mode}) or
234
$this->error("could not write $filename-new: $!");
235
$this->{format}->beginfile;
236
foreach my $item (@{$filecontents{$file}}) {
237
$this->{format}->write($fh, $this->{cache}->{$item}, $item)
238
or $this->error("could not write $filename-new: $!");
240
$this->{format}->endfile;
242
# Ensure -new is flushed.
243
$fh->flush or $this->error("could not flush $filename-new: $!");
244
# Ensure it is synced, because I've had problems with
245
# disk caching resulting in truncated files.
246
$fh->sync or $this->error("could not sync $filename-new: $!");
248
# Now rename the old file to -old (if doing backups),
249
# and put -new in its place.
250
if (-e $filename && $this->{backup}) {
251
rename($filename, $filename."-old") or
252
debug "db $this->{name}" => "rename failed: $!";
254
rename($filename."-new", $filename) or
255
$this->error("rename failed: $!");
259
$this->SUPER::shutdown(@_);
265
Joey Hess <joeyh@debian.org>