1# ex:ts=8 sw=4:
2# $OpenBSD: Persistent.pm,v 1.3 2017/11/03 15:30:12 espie Exp $
3#
4# Copyright (c) 2003-2014 Marc Espie <espie@openbsd.org>
5#
6# Permission to use, copy, modify, and distribute this software for any
7# purpose with or without fee is hereby granted, provided that the above
8# copyright notice and this permission notice appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18use strict;
19use warnings;
20
21package OpenBSD::PackageRepository::Persistent;
22our @ISA=qw(OpenBSD::PackageRepository::Distant);
23
24our %distant = ();
25
26sub may_exist
27{
28	my ($self, $name) = @_;
29	my $l = $self->list;
30	return grep {$_ eq $name } @$l;
31}
32
33sub grab_object
34{
35	my ($self, $object) = @_;
36
37	my $cmdfh = $self->{cmdfh};
38	my $getfh = $self->{getfh};
39
40	print $cmdfh "ABORT\n";
41	while (<$getfh>) {
42		last if m/^ABORTED/o;
43	}
44	print $cmdfh "GET ", $self->{path}.$object->{name}.".tgz", "\n";
45	CORE::close($cmdfh);
46	$_ = <$getfh>;
47	chomp;
48	if (m/^ERROR:/o) {
49		$self->{state}->fatal("transfer error: #1", $_);
50	}
51	if (m/^TRANSFER:\s+(\d+)/o) {
52		my $buffsize = 10 * 1024;
53		my $buffer;
54		my $size = $1;
55		my $remaining = $size;
56		my $n;
57
58		do {
59			$n = read($getfh, $buffer,
60				$remaining < $buffsize ? $remaining :$buffsize);
61			if (!defined $n) {
62				$self->{state}->fatal("Error reading: #1", $!);
63			}
64			$remaining -= $n;
65			if ($n > 0) {
66				syswrite STDOUT, $buffer;
67			}
68		} while ($n != 0 && $remaining != 0);
69	}
70	delete $self->{controller};
71	CORE::close($getfh);
72}
73
74sub maxcount
75{
76	return 1;
77}
78
79sub opened
80{
81	my $self = $_[0];
82	my $k = $self->{host};
83	if (!defined $distant{$k}) {
84		$distant{$k} = [];
85	}
86	return $distant{$k};
87}
88
89sub list
90{
91	my ($self) = @_;
92	if (!defined $self->{list}) {
93		if (!defined $self->{controller}) {
94			$self->initiate;
95		}
96		my $cmdfh = $self->{cmdfh};
97		my $getfh = $self->{getfh};
98		my $path = $self->{path};
99		my $l = [];
100		print $cmdfh "LIST $path\n";
101		$_ = <$getfh>;
102		if (!defined $_) {
103			$self->{state}->fatal("Could not initiate #1 session",
104			    $self->urlscheme);
105		}
106		chomp;
107		if (m/^ERROR:/o) {
108			$self->{state}->fatal("#1", $_);
109		}
110		if (!m/^SUCCESS:/o) {
111			$self->{state}->fatal("Synchronization error");
112		}
113		while (<$getfh>) {
114			chomp;
115			last if $_ eq '';
116			push(@$l, $_);
117		}
118		$self->{list} = $l;
119	}
120	return $self->{list};
121}
122
123sub cleanup
124{
125	my $self = shift;
126	if (defined $self->{controller}) {
127		my $cmdfh = $self->{cmdfh};
128		my $getfh = $self->{getfh};
129		print $cmdfh "ABORT\nBYE\nBYE\n";
130		CORE::close($cmdfh);
131		CORE::close($getfh);
132		waitpid($self->{controller}, 0);
133		delete $self->{controller};
134	}
135}
136
137sub dont_cleanup
138{
139	my $self = shift;
140	CORE::close($self->{cmdfh});
141	CORE::close($self->{getfh});
142	delete $self->{controller};
143}
144
145sub reinitialize
146{
147	my $self = shift;
148	$self->initiate;
149}
150
1511;
152