diff options
Diffstat (limited to 'lib/PublicInbox/InboxWritable.pm')
-rw-r--r-- | lib/PublicInbox/InboxWritable.pm | 122 |
1 files changed, 40 insertions, 82 deletions
diff --git a/lib/PublicInbox/InboxWritable.pm b/lib/PublicInbox/InboxWritable.pm index c2baeba6..8e95cb28 100644 --- a/lib/PublicInbox/InboxWritable.pm +++ b/lib/PublicInbox/InboxWritable.pm @@ -1,25 +1,18 @@ -# Copyright (C) 2018-2021 all contributors <meta@public-inbox.org> +# Copyright (C) all contributors <meta@public-inbox.org> # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> # Extends read-only Inbox for writing package PublicInbox::InboxWritable; use strict; use v5.10.1; -use parent qw(PublicInbox::Inbox Exporter); +use parent qw(PublicInbox::Inbox PublicInbox::Umask Exporter); use PublicInbox::Import; +use PublicInbox::IO qw(read_all); use PublicInbox::Filter::Base qw(REJECT); use Errno qw(ENOENT); our @EXPORT_OK = qw(eml_from_path); use Fcntl qw(O_RDONLY O_NONBLOCK); -use constant { - PERM_UMASK => 0, - OLD_PERM_GROUP => 1, - OLD_PERM_EVERYBODY => 2, - PERM_GROUP => 0660, - PERM_EVERYBODY => 0664, -}; - sub new { my ($class, $ibx, $creat_opt) = @_; return $ibx if ref($ibx) eq $class; @@ -47,7 +40,7 @@ sub _init_v1 { require PublicInbox::Msgmap; my $sidx = PublicInbox::SearchIdx->new($self, 1); # just create $sidx->begin_txn_lazy; - my $mm = PublicInbox::Msgmap->new($self->{inboxdir}, 1); + my $mm = PublicInbox::Msgmap->new_file($self, 1); if (defined $skip_artnum) { $mm->{dbh}->begin_work; $mm->skip_artnum($skip_artnum); @@ -122,22 +115,17 @@ sub filter { sub eml_from_path ($) { my ($path) = @_; if (sysopen(my $fh, $path, O_RDONLY|O_NONBLOCK)) { - return unless -f $fh; # no FIFOs or directories - my $str = do { local $/; <$fh> } or return; - PublicInbox::Eml->new(\$str); + return unless -f $fh && -s _; # no FIFOs or directories + PublicInbox::Eml->new(\(my $str = read_all($fh, -s _))); } else { # ENOENT is common with Maildir warn "failed to open $path: $!\n" if $! != ENOENT; undef; } } -sub _each_maildir_fn { - my ($fn, $im, $self) = @_; - if ($fn =~ /:2,([A-Za-z]*)\z/) { - my $fl = $1; - return if $fl =~ /[DT]/; # no Drafts or Trash for public - } - my $eml = eml_from_path($fn) or return; +sub _each_maildir_eml { + my ($fn, $kw, $eml, $im, $self) = @_; + return if grep(/\Adraft\z/, @$kw); if ($self && (my $filter = $self->filter($im))) { my $ret = $filter->scrub($eml) or return; return if $ret == REJECT(); @@ -146,6 +134,7 @@ sub _each_maildir_fn { $im->add($eml); } +# XXX does anybody use this? sub import_maildir { my ($self, $dir) = @_; foreach my $sub (qw(cur new tmp)) { @@ -154,8 +143,8 @@ sub import_maildir { my $im = $self->importer(1); my @self = $self->filter($im) ? ($self) : (); require PublicInbox::MdirReader; - PublicInbox::MdirReader::maildir_each_file(\&_each_maildir_fn, - $im, @self); + PublicInbox::MdirReader->new->maildir_each_eml($dir, + \&_each_maildir_eml, $im, @self); $im->done; } @@ -172,71 +161,13 @@ sub _mbox_eml_cb { # MboxReader->mbox* callback sub import_mbox { my ($self, $fh, $variant) = @_; require PublicInbox::MboxReader; - my $cb = PublicInbox::MboxReader->can($variant) or + my $cb = PublicInbox::MboxReader->reads($variant) or die "$variant not supported\n"; my $im = $self->importer(1); $cb->(undef, $fh, \&_mbox_eml_cb, $im, $self->filter); $im->done; } -sub _read_git_config_perm { - my ($self) = @_; - chomp(my $perm = $self->git->qx('config', 'core.sharedRepository')); - $perm; -} - -sub _git_config_perm { - my $self = shift; - my $perm = scalar @_ ? $_[0] : _read_git_config_perm($self); - return PERM_UMASK if (!defined($perm) || $perm eq ''); - return PERM_UMASK if ($perm eq 'umask'); - return PERM_GROUP if ($perm eq 'group'); - if ($perm =~ /\A(?:all|world|everybody)\z/) { - return PERM_EVERYBODY; - } - return PERM_GROUP if ($perm =~ /\A(?:true|yes|on|1)\z/); - return PERM_UMASK if ($perm =~ /\A(?:false|no|off|0)\z/); - - my $i = oct($perm); - return PERM_UMASK if ($i == PERM_UMASK); - return PERM_GROUP if ($i == OLD_PERM_GROUP); - return PERM_EVERYBODY if ($i == OLD_PERM_EVERYBODY); - - if (($i & 0600) != 0600) { - die "core.sharedRepository mode invalid: ". - sprintf('%.3o', $i) . "\nOwner must have permissions\n"; - } - ($i & 0666); -} - -sub _umask_for { - my ($perm) = @_; # _git_config_perm return value - my $rv = $perm; - return umask if $rv == 0; - - # set +x bit if +r or +w were set - $rv |= 0100 if ($rv & 0600); - $rv |= 0010 if ($rv & 0060); - $rv |= 0001 if ($rv & 0006); - (~$rv & 0777); -} - -sub with_umask { - my ($self, $cb, @arg) = @_; - my $old = umask($self->{umask} //= umask_prepare($self)); - my $rv = eval { $cb->(@arg) }; - my $err = $@; - umask $old; - die $err if $err; - $rv; -} - -sub umask_prepare { - my ($self) = @_; - my $perm = _git_config_perm($self); - _umask_for($perm); -} - sub cleanup ($) { delete @{$_[0]}{qw(over mm git search)}; } @@ -248,4 +179,31 @@ sub git_dir_latest { "$self->{inboxdir}/git/$$max.git" : undef; } +# for unconfigured inboxes +sub detect_indexlevel ($) { + my ($ibx) = @_; + + my $over = $ibx->over; + my $srch = $ibx->search; + delete @$ibx{qw(over search)}; # don't leave open FDs lying around + + # brand new or never before indexed inboxes default to full + return 'full' unless $over; + my $l = 'basic'; + return $l unless $srch; + if (my $xdb = $srch->xdb) { + $l = 'full'; + my $m = $xdb->get_metadata('indexlevel'); + if ($m eq 'medium') { + $l = $m; + } elsif ($m ne '') { + warn <<""; +$ibx->{inboxdir} has unexpected indexlevel in Xapian: $m + + } + $ibx->{-skip_docdata} = 1 if $xdb->get_metadata('skip_docdata'); + } + $l; +} + 1; |