From d66db7686d6b59e9fff9cf925321fe4a3bfdd484 Mon Sep 17 00:00:00 2001 From: espie Date: Thu, 17 Mar 2022 21:45:51 +0000 Subject: [PATCH] add some extra logic to prevent moving files around when this is possible. Specifically, we created pkg.XXXX temp files for updates to work. When I added tied files, I generalized this to installs as well, because it was becoming too complex. Forward a few years: - we have tags and define-tag, so we can deem a lot of UpdateSets "safe" (because they don't run command during the deletion/installation, but at the end, so they won't see unwanted files) - the tied logic is well-proven With this diff: - installs will again extract files directly in-place, so that install is (mostly) chown + utimes. - updates will extract files with new names directly in-place - tied files that didn't change names will have zero churn (instead of link to pkg.XXXX, rm orig file, mv pkg.XXXX back to orig file) After lots of tests involving somewhat broken things. Okay sthen@ (if it breaks it's easy to revert, but the speed-up for stuff like texlive minor updates is significant) --- usr.sbin/pkg_add/OpenBSD/Add.pm | 69 ++++++++++++++++++++------- usr.sbin/pkg_add/OpenBSD/Delete.pm | 3 +- usr.sbin/pkg_add/OpenBSD/UpdateSet.pm | 3 +- usr.sbin/pkg_add/OpenBSD/Vstat.pm | 4 +- 4 files changed, 58 insertions(+), 21 deletions(-) diff --git a/usr.sbin/pkg_add/OpenBSD/Add.pm b/usr.sbin/pkg_add/OpenBSD/Add.pm index cc735f4bc97..189406e79c7 100644 --- a/usr.sbin/pkg_add/OpenBSD/Add.pm +++ b/usr.sbin/pkg_add/OpenBSD/Add.pm @@ -1,5 +1,5 @@ # ex:ts=8 sw=4: -# $OpenBSD: Add.pm,v 1.187 2022/03/09 12:27:51 espie Exp $ +# $OpenBSD: Add.pm,v 1.188 2022/03/17 21:45:51 espie Exp $ # # Copyright (c) 2003-2014 Marc Espie # @@ -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); + 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}; } - 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); } diff --git a/usr.sbin/pkg_add/OpenBSD/Delete.pm b/usr.sbin/pkg_add/OpenBSD/Delete.pm index b7748d3e506..246ee8f3879 100644 --- a/usr.sbin/pkg_add/OpenBSD/Delete.pm +++ b/usr.sbin/pkg_add/OpenBSD/Delete.pm @@ -1,5 +1,5 @@ # ex:ts=8 sw=4: -# $OpenBSD: Delete.pm,v 1.160 2019/07/24 18:05:26 espie Exp $ +# $OpenBSD: Delete.pm,v 1.161 2022/03/17 21:45:51 espie Exp $ # # Copyright (c) 2003-2014 Marc Espie # @@ -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) { diff --git a/usr.sbin/pkg_add/OpenBSD/UpdateSet.pm b/usr.sbin/pkg_add/OpenBSD/UpdateSet.pm index 0aa0512598e..13bfe46594e 100644 --- a/usr.sbin/pkg_add/OpenBSD/UpdateSet.pm +++ b/usr.sbin/pkg_add/OpenBSD/UpdateSet.pm @@ -1,5 +1,5 @@ # ex:ts=8 sw=4: -# $OpenBSD: UpdateSet.pm,v 1.85 2019/07/04 09:47:09 espie Exp $ +# $OpenBSD: UpdateSet.pm,v 1.86 2022/03/17 21:45:52 espie Exp $ # # Copyright (c) 2007-2010 Marc Espie # @@ -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; } diff --git a/usr.sbin/pkg_add/OpenBSD/Vstat.pm b/usr.sbin/pkg_add/OpenBSD/Vstat.pm index 45f3e745ee9..0ddec077ffa 100644 --- a/usr.sbin/pkg_add/OpenBSD/Vstat.pm +++ b/usr.sbin/pkg_add/OpenBSD/Vstat.pm @@ -1,5 +1,5 @@ # ex:ts=8 sw=4: -# $OpenBSD: Vstat.pm,v 1.69 2017/10/22 08:55:22 espie Exp $ +# $OpenBSD: Vstat.pm,v 1.70 2022/03/17 21:45:52 espie Exp $ # # Copyright (c) 2003-2007 Marc Espie # @@ -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); } -- 2.20.1