From 2276866c65b5cff1e4b2dfc561c0e6ba58fd7c98 Mon Sep 17 00:00:00 2001
From: "Eric Wong (Contractor, The Linux Foundation)" <e@80x24.org>
Date: Fri, 30 Mar 2018 18:03:01 +0000
Subject: [PATCH] search: move permissions handling to InboxWritable

We'll be making sure V2Writable uses this.
---
 lib/PublicInbox/InboxWritable.pm | 71 ++++++++++++++++++++++++++++
 lib/PublicInbox/SearchIdx.pm     | 80 ++++----------------------------
 t/search.t                       | 28 +++++------
 3 files changed, 93 insertions(+), 86 deletions(-)

diff --git a/lib/PublicInbox/InboxWritable.pm b/lib/PublicInbox/InboxWritable.pm
index 82834f08..92b9016e 100644
--- a/lib/PublicInbox/InboxWritable.pm
+++ b/lib/PublicInbox/InboxWritable.pm
@@ -10,6 +10,14 @@ use PublicInbox::Import;
 use PublicInbox::Filter::Base;
 *REJECT = *PublicInbox::Filter::Base::REJECT;
 
+use constant {
+	PERM_UMASK => 0,
+	OLD_PERM_GROUP => 1,
+	OLD_PERM_EVERYBODY => 2,
+	PERM_GROUP => 0660,
+	PERM_EVERYBODY => 0664,
+};
+
 sub new {
 	my ($class, $ibx) = @_;
 	bless $ibx, $class;
@@ -157,4 +165,67 @@ sub import_mbox {
 	$im->done;
 }
 
+sub _read_git_config_perm {
+	my ($self) = @_;
+	my @cmd = qw(config);
+	if (($self->{version} ||= 1) == 2) {
+		push @cmd, "--file=$self->{mainrepo}/all.git/config";
+	}
+	chomp(my $perm = $self->git->qx(@cmd, 'core.sharedRepository'));
+	$perm;
+}
+
+sub _git_config_perm {
+	my $self = shift;
+	my $perm = scalar @_ ? $_[0] : _read_git_config_perm($self);
+	return PERM_GROUP 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) = @_;
+	my $old = umask $self->{umask};
+	my $rv = eval { $cb->() };
+	my $err = $@;
+	umask $old;
+	die $err if $err;
+	$rv;
+}
+
+sub umask_prepare {
+	my ($self) = @_;
+	my $perm = _git_config_perm($self);
+	my $umask = _umask_for($perm);
+	$self->{umask} = $umask;
+}
+
 1;
diff --git a/lib/PublicInbox/SearchIdx.pm b/lib/PublicInbox/SearchIdx.pm
index a234c8c3..9638e0c5 100644
--- a/lib/PublicInbox/SearchIdx.pm
+++ b/lib/PublicInbox/SearchIdx.pm
@@ -11,6 +11,7 @@ use strict;
 use warnings;
 use base qw(PublicInbox::Search PublicInbox::Lock);
 use PublicInbox::MIME;
+use PublicInbox::InboxWritable;
 use PublicInbox::MID qw/mid_clean id_compress mid_mime mids references/;
 use PublicInbox::MsgIter;
 use Carp qw(croak);
@@ -18,11 +19,6 @@ use POSIX qw(strftime);
 require PublicInbox::Git;
 
 use constant {
-	PERM_UMASK => 0,
-	OLD_PERM_GROUP => 1,
-	OLD_PERM_EVERYBODY => 2,
-	PERM_GROUP => 0660,
-	PERM_EVERYBODY => 0664,
 	BATCH_BYTES => 1_000_000,
 	DEBUG => !!$ENV{DEBUG},
 };
@@ -62,20 +58,19 @@ sub new {
 				PublicInbox::AltId->new($ibx, $_);
 			} @$altid ];
 		}
-		$git = $ibx->git;
-	} else {
-		$git = PublicInbox::Git->new($git_dir); # v1 only
+	} else { # v1
+		$ibx = { mainrepo => $git_dir, version => 1 };
 	}
+	$ibx = PublicInbox::InboxWritable->new($ibx);
 	require Search::Xapian::WritableDatabase;
 	my $self = bless {
 		mainrepo => $mainrepo,
-		git => $git,
+		-inbox => $ibx,
+		git => $ibx->git,
 		-altid => $altid,
 		version => $version,
 	}, $class;
-	my $perm = $self->_git_config_perm;
-	my $umask = _umask_for($perm);
-	$self->{umask} = $umask;
+	$ibx->umask_prepare;
 	if ($version == 1) {
 		$self->{lock_path} = "$mainrepo/ssoma.lock";
 	} elsif ($version == 2) {
@@ -648,7 +643,7 @@ sub do_cat_mail {
 
 sub index_sync {
 	my ($self, $opts) = @_;
-	with_umask($self, sub { $self->_index_sync($opts) });
+	$self->{-inbox}->with_umask(sub { $self->_index_sync($opts) })
 }
 
 sub batch_adjust ($$$$) {
@@ -846,65 +841,6 @@ sub merge_threads {
 	});
 }
 
-sub _read_git_config_perm {
-	my ($self) = @_;
-	my @cmd = qw(config);
-	if ($self->{version} == 2) {
-		push @cmd, "--file=$self->{mainrepo}/all.git/config";
-	}
-	my $fh = $self->{git}->popen(@cmd, 'core.sharedRepository');
-	local $/ = "\n";
-	my $perm = <$fh>;
-	chomp $perm if defined $perm;
-	$perm;
-}
-
-sub _git_config_perm {
-	my $self = shift;
-	my $perm = scalar @_ ? $_[0] : _read_git_config_perm($self);
-	return PERM_GROUP 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) = @_;
-	my $old = umask $self->{umask};
-	my $rv = eval { $cb->() };
-	my $err = $@;
-	umask $old;
-	die $err if $err;
-	$rv;
-}
-
 sub DESTROY {
 	# order matters for unlocking
 	$_[0]->{xdb} = undef;
diff --git a/t/search.t b/t/search.t
index ccf0f746..9ab15f77 100644
--- a/t/search.t
+++ b/t/search.t
@@ -18,6 +18,7 @@ ok($@, "exception raised on non-existent DB");
 my $rw = PublicInbox::SearchIdx->new($git_dir, 1);
 $rw->_xdb_acquire;
 $rw->_xdb_release;
+my $ibx = $rw->{-inbox};
 $rw = undef;
 my $ro = PublicInbox::Search->new($git_dir);
 my $rw_commit = sub {
@@ -28,26 +29,25 @@ my $rw_commit = sub {
 
 {
 	# git repository perms
-	is(PublicInbox::SearchIdx->_git_config_perm(undef),
-	   &PublicInbox::SearchIdx::PERM_GROUP,
+	is($ibx->_git_config_perm(), &PublicInbox::InboxWritable::PERM_GROUP,
 	   "undefined permission is group");
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('0644')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('0644')),
 	   0022, "644 => umask(0022)");
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('0600')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('0600')),
 	   0077, "600 => umask(0077)");
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('0640')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('0640')),
 	   0027, "640 => umask(0027)");
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('group')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('group')),
 	   0007, 'group => umask(0007)');
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('everybody')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('everybody')),
 	   0002, 'everybody => umask(0002)');
-	is(PublicInbox::SearchIdx::_umask_for(
-	     PublicInbox::SearchIdx->_git_config_perm('umask')),
+	is(PublicInbox::InboxWritable::_umask_for(
+	     PublicInbox::InboxWritable->_git_config_perm('umask')),
 	   umask, 'umask => existing umask');
 }
 
-- 
2.51.0