I got a new slightly different one.
Specifically, the old one has a "fun" failure mode in case
an old package got broken and is missing files.
The heuristics correctly deduces that the files are not
there, so it extracts in-place... then pkg_delete promptly
deletes what it believes to be files from the old package!
so the broken install stays broken.
The fix is fairly obvious: I store a hash of filenames not to
delete in the current_set, instead of doing it only for tied
objects (other objects we don't quite know where they live
in the old plist, nor do we care all that much)
(I could also probably check modes and owners for tied files
since we do a stat anyway, but new files will have to get
utime'd to the new ts, so I doubt I'll see any gain from that,
and it gets way too complicated for its own good)
Index: OpenBSD/Add.pm
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/Add.pm,v
retrieving revision 1.187
diff -u -p -r1.187 Add.pm
--- OpenBSD/Add.pm 9 Mar 2022 12:27:51 -0000 1.187
+++ OpenBSD/Add.pm 16 Mar 2022 10:33:19 -0000
@@ -466,6 +466,7 @@ sub find_safe_dir
my $fullname = $self->fullname;
my $filename = $state->{destdir}.$fullname;
my $d = dirname($filename);
+ my $orig = $d;
# we go back up until we find an existing directory.
# hopefully this will be on the same file system.
@@ -483,6 +484,12 @@ sub find_safe_dir
if (!-e _ && !$state->{not}) {
$state->make_path($d, $fullname);
}
+ if ($state->{current_set}{simple_update} &&
+ $d eq $orig &&
+ !-e $filename) {
+ $self->{avoid_temp} = $filename;
+ }
+
return $d;
}
@@ -503,6 +510,18 @@ sub create_temp
return ($fh, $tempname);
}
+sub may_create_temp
+{
+ my ($self, $d, $state) = @_;
+ if ($self->{avoid_temp}) {
+ if (open(my $fh, '>', $self->{avoid_temp})) {
+ return ($fh, $self->{avoid_temp});
+ }
+ }
+ delete $self->{avoid_temp};
+ return $self->create_temp($d, $state);
+}
+
sub tie
{
my ($self, $state) = @_;
@@ -513,14 +532,22 @@ sub tie
$self->SUPER::extract($state);
my $d = $self->find_safe_dir($state);
+ my $src = $self->{tieto}->realname($state);
+ my $dest = $self->realname($state);
+ if ($state->{current_set}{simple_update} && $src eq $dest) {
+ $state->say("No name change on tied file #1", $src)
+ if $state->verbose >= 3;
+ $state->{current_set}{dont_delete}{$dest} = 1;
+ $self->{avoid_temp} = 1;
+ return;
+ }
if ($state->{not}) {
$state->say("link #1 -> #2",
$self->name, $d) if $state->verbose >= 3;
} else {
- my ($fh, $tempname) = $self->create_temp($d, $state);
+ my ($fh, $tempname) = $self->may_create_temp($d, $state);
return if !defined $tempname;
- my $src = $self->{tieto}->realname($state);
unlink($tempname);
$state->say("link #1 -> #2", $src, $tempname)
if $state->verbose >= 3;
@@ -528,6 +555,7 @@ sub tie
}
}
+
sub extract
{
my ($self, $state, $file) = @_;
@@ -540,13 +568,16 @@ sub extract
$self->name, $d) if $state->verbose >= 3;
$state->{archive}->skip;
} else {
- my ($fh, $tempname) = $self->create_temp($d, $state);
- if (!defined $tempname) {
+ my ($fh, $filename) = $self->may_create_temp($d, $state);
+ if (!defined $filename) {
$state->{archive}->skip;
return;
}
- $state->say("extract #1 -> #2", $self->name, $tempname)
+ if ($self->{avoid_temp}) {
+ $state->{current_set}{dont_delete}{$filename} = 1;
+ }
+ $state->say("extract #1 -> #2", $self->name, $filename)
if $state->verbose >= 3;
@@ -555,7 +586,7 @@ sub extract
$self->stringize);
}
$file->extract_to_fh($fh);
- $self->may_check_digest($tempname, $state);
+ $self->may_check_digest($filename, $state);
}
}
@@ -576,17 +607,21 @@ sub install
} elsif (defined $self->{symlink}) {
symlink($self->{symlink}, $destdir.$fullname);
} else {
- if (!defined $self->{tempname}) {
- return if $state->allow_nonroot($fullname);
- $state->fatal("No tempname for #1", $fullname);
- }
- rename($self->{tempname}, $destdir.$fullname) or
- $state->fatal("can't move #1 to #2: #3",
- $self->{tempname}, $fullname, $!);
- $state->say("moving #1 -> #2",
- $self->{tempname}, $destdir.$fullname)
- if $state->verbose >= 5;
- delete $self->{tempname};
+ if (defined $self->{avoid_temp}) {
+ delete $self->{avoid_temp};
+ } else {
+ if (!defined $self->{tempname}) {
+ return if $state->allow_nonroot($fullname);
+ $state->fatal("No tempname for #1", $fullname);
+ }
+ rename($self->{tempname}, $destdir.$fullname) or
+ $state->fatal("can't move #1 to #2: #3",
+ $self->{tempname}, $fullname, $!);
+ $state->say("moving #1 -> #2",
+ $self->{tempname}, $destdir.$fullname)
+ if $state->verbose >= 5;
+ delete $self->{tempname};
+ }
}
$self->set_modes($state, $destdir.$fullname);
}
Index: OpenBSD/Delete.pm
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/Delete.pm,v
retrieving revision 1.160
diff -u -p -r1.160 Delete.pm
--- OpenBSD/Delete.pm 24 Jul 2019 18:05:26 -0000 1.160
+++ OpenBSD/Delete.pm 16 Mar 2022 10:33:19 -0000
@@ -449,6 +449,7 @@ sub delete
{
my ($self, $state) = @_;
my $realname = $self->realname($state);
+ return if defined $state->{current_set}{dont_delete}{$realname};
if (defined $self->{symlink}) {
if (-l $realname) {
Index: OpenBSD/UpdateSet.pm
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/UpdateSet.pm,v
retrieving revision 1.85
diff -u -p -r1.85 UpdateSet.pm
--- OpenBSD/UpdateSet.pm 4 Jul 2019 09:47:09 -0000 1.85
+++ OpenBSD/UpdateSet.pm 16 Mar 2022 10:33:20 -0000
@@ -120,6 +120,7 @@ sub cleanup
delete $self->{solver};
delete $self->{known_mandirs};
delete $self->{known_displays};
+ delete $self->{dont_delete};
$self->mark_as_finished;
}
Index: OpenBSD/Vstat.pm
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/Vstat.pm,v
retrieving revision 1.69
diff -u -p -r1.69 Vstat.pm
--- OpenBSD/Vstat.pm 22 Oct 2017 08:55:22 -0000 1.69
+++ OpenBSD/Vstat.pm 16 Mar 2022 10:33:20 -0000
@@ -217,7 +217,7 @@ sub remove_directory
{
my ($self, $name, $o) = @_;
$self->{v}[0]->{$name} = OpenBSD::Vstat::Object::Directory->new($name,
- $self->{state}->{current_set}, $o);
+ $self->{state}{current_set}, $o);
}