-sub lockreadbugmerge {
- local ($lref, $location) = @_;
- local $data;
- if (!($data = &lockreadbug($lref, $location))) { return ( 0, undef ); }
- if (!length($data{mergedwith})) { return ( 1, $data ); }
- &unfilelock;
- &filelock('lock/merge');
- if (!&lockreadbug($lref, $location)) { &unfilelock; return ( 0, undef ); }
- return ( 2, $data );
-}
-
-sub getbuglocation {
- my ( $bugnum, $ext ) = @_;
- my $archdir = sprintf "%02d", $bugnum % 100;
- return 'archive' if ( -r "$gSpoolDir/archive/$archdir/$bugnum.$ext" );
- return 'db-h' if ( -r "$gSpoolDir/db-h/$archdir/$bugnum.$ext" );
- return 'db' if ( -r "$gSpoolDir/db/$bugnum.$ext" );
- return undef;
-}
-
-sub getlocationpath {
- my ($location) = @_;
- if ($location eq 'archive') {
- return "$gSpoolDir/archive";
- } elsif ($location eq 'db') {
- return "$gSpoolDir/db";
- } else {
- return "$gSpoolDir/db-h";
- }
-}
-
-sub getbugcomponent {
- my ($bugnum, $ext, $location) = @_;
-
- $location = getbuglocation($bugnum, $ext) unless defined $location;
- my $dir = getlocationpath($location);
- return undef unless $dir;
- if ($location eq 'db') {
- return "$dir/$bugnum.$ext";
- } else {
- my $hash = get_hashname($bugnum);
- return "$dir/$hash/$bugnum.$ext";
- }
-}
-
-sub readbug {
- local ($lref, $location) = @_;
- my $status = getbugcomponent($lref, 'status', $location);
- return undef unless defined $status;
- if (!open(S,$status)) { return undef; }
- my %data;
- chop($data{originator}= <S>);
- chop($data{date}= <S>);
- chop($data{subject}= <S>);
- chop($data{msgid}= <S>);
- chop($data{package}= <S>);
- chop($data{keywords}= <S>);
- chop($data{done}= <S>);
- chop($data{forwarded}= <S>);
- chop($data{mergedwith}= <S>);
- chop($data{severity}= <S>);
- chop($data{versions}= <S>);
- chop($data{fixed_versions}= <S>);
- close(S);
- $data{severity} = 'normal' if $data{severity} eq '';
- return \%data;
-}
-
-sub lockreadbug {
- local ($lref, $location) = @_;
- &filelock("lock/$lref");
- my $data = readbug($lref, $location);
- &unfilelock unless defined $data;
- return $data;
-}
-
-sub writebug {
- local ($ref, $data, $location) = @_;
- my $change;
- my $status = getbugcomponent($ref, 'status', $location);
- &quit("can't find location for $ref") unless defined $status;
- open(S,"> $status.new") || &quit("opening $status.new: $!");
- print(S
- "$data->{originator}\n".
- "$data->{date}\n".
- "$data->{subject}\n".
- "$data->{msgid}\n".
- "$data->{package}\n".
- "$data->{keywords}\n".
- "$data->{done}\n".
- "$data->{forwarded}\n".
- "$data->{mergedwith}\n".
- "$data->{severity}\n".
- "$data->{versions}\n".
- "$data->{fixed_versions}\n") || &quit("writing $status.new: $!");
- close(S) || &quit("closing $status.new: $!");
- if (-e $status) {
- $change = 'change';
- } else {
- $change = 'new';
- }
- rename("$status.new",$status) ||
- &quit("installing new $status: $!");
- &bughook($change,$ref,
- "$data->{originator}\n".
- "$data->{date}\n".
- "$data->{subject}\n".
- "$data->{msgid}\n".
- "$data->{package}\n".
- "$data->{keywords}\n".
- "$data->{done}\n".
- "$data->{forwarded}\n".
- "$data->{mergedwith}\n".
- "$data->{severity}\n".
- "$data->{versions}\n".
- "$data->{fixed_versions}\n");
-}
-
-sub unlockwritebug {
- writebug(@_);
- &unfilelock;
-}
-
-sub filelock {
- # NB - NOT COMPATIBLE WITH `with-lock'
- local ($lockfile,$flockpushno,$evalstring,$count,$errors,@s1,@s2) = @_;
- $flockpushno= $#filelocks+1;
- $count= 10; $errors= '';
- for (;;) {
- $evalstring= "
- open(FLOCK${flockpushno},\"> \$lockfile\") || die \"open: \$!\";
- \$flockwant= pack(\$flockstruct,&F_WRLCK,0,0,1,0);".
- ($] >= 5.000 ? "
- fcntl(FLOCK$flockpushno,&F_SETLK,\$flockwant) || die \"setlk: \$!\";" : "
- \$z= syscall(&SYS_fcntl,fileno(FLOCK$flockpushno),&F_SETLK,\$flockwant) < 0
- && die \"syscall fcntl setlk: \$!\";") ."
- (\@s1= lstat(\$lockfile)) || die \"lstat: \$!\";
- (\@s2= stat(FLOCK$flockpushno)) || die \"fstat: \$!\";
- join(',',\@s1) eq join(',',\@s2) || die \"file switched\";
- 1;
- ";
- last if eval $evalstring;
- $errors .= $@;
- eval "close(FLOCK$flockpushno);";
- if (--$count <=0) {
- $errors =~ s/\n+$//;
- &quit("failed to get lock on file $lockfile: $errors // $evalstring");
- }
- sleep 10;
- }
- push(@cleanups,'unfilelock');
- push(@filelocks,$lockfile);
-}
-
-sub unfilelock {
- if (@filelocks == 0) {
- warn "unfilelock called with no active filelocks!\n";
- return;
- }
- local ($lockfile) = pop(@filelocks);
- pop(@cleanups);
- eval 'close(FLOCK'.($#filelocks+1).');' || warn "failed to close lock file $lockfile: $!";
- unlink($lockfile) || warn "failed to remove lock file $lockfile: $!";
-}
-
-sub quit {
- print DEBUG "quitting >$_[0]<\n";
- local ($u);
- while ($u= $cleanups[$#cleanups]) { &$u; }
- die "*** $_[0]\n";
-}
-