From e269aef941bd57d8e9c883c8a4c705dc3ada52b0 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Tue, 10 Oct 2006 00:45:54 +0200 Subject: [PATCH] Race-free edit_group() using filedb_atomic_edit() --- cgi/Git/RepoCGI.pm | 19 ++++++++++++++++++- cgi/p/editproj.cgi | 32 +++++++++++--------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/cgi/Git/RepoCGI.pm b/cgi/Git/RepoCGI.pm index 6690d28..213e30c 100644 --- a/cgi/Git/RepoCGI.pm +++ b/cgi/Git/RepoCGI.pm @@ -9,7 +9,8 @@ use warnings; BEGIN { our $VERSION = '0.1'; our @ISA = qw(Exporter); - our @EXPORT = qw(scrypt html_esc jailed_file filedb_atomic_append); + our @EXPORT = qw(scrypt html_esc jailed_file + filedb_atomic_append filedb_atomic_edit); use CGI qw(:standard :escapeHTML -nosticky); use CGI::Util qw(unescape); @@ -160,5 +161,21 @@ sub filedb_atomic_append { $id; } +sub filedb_atomic_edit { + my ($file, $fn) = @_; + + open my $src, $file or die "$file open for reading failed: $!"; + my $dst = lock_file($file); + + while (<$src>) { + print $dst $fn($_) or die "$file(l) write failed: $!"; + } + + close $dst or die "$file(l) close failed: $!"; + close $src; + + unlock_file($file); +} + 1; diff --git a/cgi/p/editproj.cgi b/cgi/p/editproj.cgi index 5f115b3..f81b62f 100755 --- a/cgi/p/editproj.cgi +++ b/cgi/p/editproj.cgi @@ -59,28 +59,18 @@ sub save_proj_data { sub edit_group { my ($gid, $name, $pwd, $xtra) = @_; - # racy! - # at least basic protection, but there's still race window; I suck - my ($size, $__, $mtime) = splice(@{[stat(jailed_file("/etc/group"))]}, 7, 3); - open F, jailed_file("/etc/group") or die "group failed: $!"; - open G, ">".jailed_file("/etc/group.$$") or die "repogroup failed: $!"; - while () { - chomp; - if ($name eq (split /:/)[0]) { - s/::([^:]*)$/:$1/ and $xtra = ":$xtra"; - print G "$name:$pwd:$gid:$xtra\n"; - } else { - print G "$_\n"; + filedb_atomic_edit($file, + sub { + $_ = $_[0]; + chomp; + if ($name eq (split /:/)[0]) { + s/::([^:]*)$/:$1/ and $xtra = ":$xtra"; + return "$name:$pwd:$gid:$xtra\n"; + } else { + return "$_\n"; + } } - } - close G; - close F; - my ($size2, $__2, $mtime2) = splice(@{[stat(jailed_file("/etc/group")]}, 7, 3); - if ($size2 ne $size or $mtime2 ne $mtime) { - die "sorry, hit a race window; please try submitting again"; - } - chmod 0664, jailed_file("/etc/group.$$") or die "chmod failed: $!"; - rename jailed_file("/etc/group.$$"), jailed_file("/etc/group") or die "rename failed: $!"; + ); } sub update_project { -- 2.11.4.GIT