Subject: | Mail::Box::File::_write_replace fails on Windows |
Mail::Box::File::_write_replace has this line of code in it, right
before it tries to rename the new file on top of the old one:
unlink $filename if $windows;
The idea here is that since Windows doesn't allow a rename on top of an
existing file, we need to delete the existing file right before we try
to do the rename.
The problem with this is that Mail::Box::Parser still has the file open
when this line of code runs, which means that the unlink doesn't fully
succeed. When you delete an open file in Windows, the
delete "succeeds", but the file stays there until everybody who has it
open closes it.
As a result, the subsequent line of code:
unless(move $tmpnew, $filename)
fails.
The best way I could come up with to fix this problem was to modify
Mail::Box::Parser to support a delayed restart, i.e., close the file
now but don't reopen it until I tell you to. I've attached the
necessary patches to implement this change. I don't know if this is
the Right Way to fix this or the way you want to do it, but it seems to
work for me.
Subject: | diff |
--- /usr/lib/perl5/site_perl/5.8/Mail/Box/Parser.pm~ 2007-11-28 04:47:08.000000000 -0500
+++ /usr/lib/perl5/site_perl/5.8/Mail/Box/Parser.pm 2007-12-04 10:36:38.966250000 -0500
@@ -67,21 +67,35 @@
$self->closeFile;
}
+sub delayed_restart()
+{ my $self = shift;
+ my $delayed_filename = $self->{delayed_restart_filename};
+
+ if ($delayed_filename) {
+ $self->openFile( {filename => $delayed_filename,
+ mode => $self->{MBP_mode}} )
+ or return;
-sub restart()
-{ my $self = shift;
- my $filename = $self->filename;
+ $self->takeFileInfo;
+ $self->log(NOTICE => "Restarted parser for file $delayed_filename");
+ }
+ else {
+ my $filename = $self->filename;
- $self->closeFile or return;
+ $self->{delayed_restart_filename} = $filename;
- $self->openFile( {filename => $filename, mode => $self->{MBP_mode}} )
- or return;
+ $self->closeFile or return;
+ $self->log(NOTICE => "Closed parser for file $filename preparing to restart");
+ }
- $self->takeFileInfo;
- $self->log(NOTICE => "Restarted parser for file $filename");
$self;
}
+sub restart()
+{ my $self = shift;
+ $self->delayed_restart && $self->delayed_restart;
+}
+
sub fileChanged()
{ my $self = shift;
--- /usr/lib/perl5/site_perl/5.8/Mail/Box/File.pm~ 2007-11-28 04:47:07.000000000 -0500
+++ /usr/lib/perl5/site_perl/5.8/Mail/Box/File.pm 2007-12-04 10:33:23.841250000 -0500
@@ -346,6 +346,8 @@
my $policy = exists $args->{policy} ? $args->{policy} : $self->{MBF_policy};
$policy ||= '';
+ $self->parser->delayed_restart;
+
my $success
= ! -e $filename ? $self->_write_new($args)
: $policy eq 'INPLACE' ? $self->_write_inplace($args)
@@ -358,7 +360,7 @@
return;
}
- $self->parser->restart;
+ $self->parser->delayed_restart;
$self;
}