unless $pass;
}
-# make sure our directories all exist, or it's hopeless.
-# Use ftp_abort here - this error should "never" happen.
+# Ensure that all configured directories actually exist and that
+# directories required to be on the same filesystem actually are on the
+# same filesystem. More precisely, ensure that rename works in the
+# circumstances where we assume it to be available.
+#
+# Use ftp_abort here - these errors should "never" happen.
{
- our $Inbox_dir; our $Scratch_dir; our $Public_dir; our $Stage_dir;
+ our $Inbox_dir; our $Scratch_dir;
+ our $Stage_dir; our $Public_dir; our $Archive_dir;
+
+ # The actual archive directory will be created if necessary, but we
+ # require its immediate parent to exist and will test moving a file there
+ # instead if the archive directory does not already exist.
+ my $archive_test_dir;
+ if (-d $Archive_dir) { $archive_test_dir = $Archive_dir }
+ else { # effectively `dirname $Archive_dir`
+ my @archive_dir = File::Spec->splitdir($Archive_dir); pop @archive_dir;
+ $archive_test_dir = File::Spec->catdir(@archive_dir);
+ }
+
for my $dir ($package_config_base, $Inbox_dir, $Scratch_dir,
- $Public_dir, $Stage_dir) {
+ $Public_dir, $Stage_dir, $archive_test_dir) {
ftp_abort("FATAL: configuration problem, $dir is not a directory")
unless -d $dir;
}
+
+ # Note that the file name used for testing is _not_ a permissible name,
+ # nor can it be produced by cleaning up a file with a permissible name.
+ my $testfilename =
+ '.+gatekeeper.test.'.$$.strftime '.{%Y-%m-%d.%H-%M-%S}', localtime;
+
+ my $infile = File::Spec->catfile($Inbox_dir, $testfilename);
+ my $scratchfile = File::Spec->catfile($Scratch_dir, $testfilename);
+ my $stagefile = File::Spec->catfile($Stage_dir, $testfilename);
+ my $pubfile = File::Spec->catfile($Public_dir, $testfilename);
+ my $arcfile = File::Spec->catfile($archive_test_dir, $testfilename);
+
+ # none of them should exist at the start of the test
+ unlink $infile, $scratchfile, $stagefile, $pubfile, $arcfile;
+
+ # test moving a file from inbox to scratch
+ {
+ sysopen my $test, $infile, O_WRONLY|O_CREAT|O_EXCL
+ or ftp_abort("create test file in inbox: $!");
+ close $test;
+ unless (rename $infile, $scratchfile and -f $scratchfile) {
+ unlink $infile;
+ ftp_abort("FATAL: could not rename file from inbox to scratchpad: $!");
+ }
+ unlink $scratchfile; # test complete
+ }
+
+ # The system mv(1) command is used to move files from scratch to staging.
+
+ # test moving a file from stage to public to archive
+ {
+ sysopen my $test, $stagefile, O_WRONLY|O_CREAT|O_EXCL
+ or ftp_abort("create test file in staging directory: $!");
+ close $test;
+ unless (rename $stagefile, $pubfile and -f $pubfile) {
+ unlink $stagefile;
+ ftp_abort("FATAL: could not rename file from staging to public: $!");
+ }
+ unless (rename $pubfile, $arcfile and -f $arcfile) {
+ unlink $pubfile;
+ ftp_abort("FATAL: could not rename file from public to archive: $!");
+ }
+ unlink $arcfile; # test complete
+ }
+ # There is a very small window where someone listing the public directory
+ # might see a test file, but it will not stay for long.
}
\f